THE ADVANCED
MACHiriE lATtGiyVGE
BOOK TOR THE
COMMODa^-64
THE ADVANCED
MACHINE LANGUAGE BOOK
FOR THE COMMODORE 64
BY: Lothar Englisch
A DATA BECKER BOOK
/^tazusB Software
P.O. BOX 7211 BRAND RAPIDS, MICH. 49510
First English Edition, September 1984
Printed in U.S.A.
Copyright (C)1984 Data Becker GmgH
Merowingerstr . 30
4000 Dusseldorf W. Germany
Copyright (C)1984 Abacus Software, Inc.
P.O. Box 7211
Grand Rapids, MI 49510
This book is copyrighted. No part of this publication may
be reproduced, stored in a retrieval system, or
transmitted in any form or by any means, electronic,
mechanical or otherwise, without the prior written
permission of DATA BECKER or ABACUS Software.
ISBN 0-916439-06-2
Table of Contents
Introduction 1
I
SECTION 1 Numbers and Arithmetic
1.1 Number representation on the Commodore 64 2
1.2 Conversion to floating-point format 22
1.3 Conversion to integer format 28
1.4 BASIC math routines < 30
1.5 BASIC floating-point routines 44
SECTION 2 Interrupts
2.1 Interrupt programming 69
2.2 The CIA 6526 . . . 74
2.3 Using the system interrupt ...80
2.4 Video controller interrupts 102
2.5 CIA 6526 interrupts 110
2.6 Using the timer 116
SECTION 3 Beyond BASIC
3.1 Kernel and BASIC extensions 131
3.2 The BASIC vectors 134
3.3 Structured programming 147
3.4 Using new keywords 160
3.5 The operating system vectors 182
3.6 Printer spooling 197
3.7 Table of BASIC keywords and tokens 209
Advanced Machine Language
Introduction
I
The material in this book builds on the fundamentals of
machine language programming as found in the book The Mach-
ine Language Book for the Commodore 64 . In this book we will
show you how to make use of many the Commodore 64 's special
features and capabilities using machine language.
The book is divided into three major sections. The
first section concerns the internal representation of num-
bers on the Commodore 64 and describes in detail how the
computer performs calculations and how its math routines can
be used from machine language. In addition to the conversion
of numbers between the various formats, the main emphasis of
this section lies in writing arithmetic functions which can
be used from BASIC with the help of the USR function.
The second section deals with a specialty of machine
language: interrupts. After explaining some of the terms,
interrupts are discussed in detail. Many sample programs
illustrate the variety of uses for interrupt handling. At
the close of this section, a machine language program demon-
strates how BASIC subroutines can be controlled with inter-
rupts .
The third and final section presents the concept of
vectors in both the BASIC interpreter and kernal. The in-
dividual vectors are described and the procedure for adding
your own commands is explained. The implementation of the
REPEAT-UNTIL structure is used to demonstrate this.
Advanced Machine Languiage
SECTION 1 Nuabers and arlthaetic
1.1 Nuaber representation on the Coaaodore 64
Your Commodore 64 uses two methods to represent numbers
internally:
You are already familiar with the first type of repre-
sentation, which is used for variables of type INTEGER.
These variables can contain only whole numbers from -32768
to ■•■32767 and can be represented in two bytes (16 bits). The
upper-most of these 16 bits is used to represent the sign of
the number.
Decimal Binary Hex
-32768
1
000
0000
0000
0000
80
00
-32767
1
000
0000
0000
0001
80
01
-32766
1
000
0000
0000
0010
80
02
-32765
1
000
0000
0000
0011
80
03
-2
1
111
1111
1111
1110
FF
FE
-1
1
111
1111
1111
1111
FF
FF
000
0000
0000
0000
00
00
1
000
0000
0000
0001
00
01
2
000
0000
0000
0010
00
02
32766
111
1111
1111
1110
7F
FE
32767
111
1111
1111
1111
7F
FF
This table illustrates how signed 16-bit numbers are
represented. You can see that it is similar to the represen-
tation of signed 8-bit numbers which can contain the valueO
-128 to -•■127 and are used for such things as relative ad-
2
Advanced Machine Language
dressing.
Integers are not suited for calculations which require
fractional values or a large value range. Floating-point
nuHbers are used for this purpose. You nay be acquainted
with this type of representation from such things as pocket
calculators that use scientific notation. Let's take a clo-
ser look at floating-point.
Since we are familiar with the decimal system, we'll
begin with it. If we want to represent a number, we first
see how many times the base of this number system, 10, is
contained within the number as a factor and divide the
number into two parts. A example should clarify this:
15 = 1.5 * 10-^1
230 = 2.3 * 10-^2
When we extend the exponential representation to include
negative exponents, we can represent all of the numbers:
5 = 5.0 * 10^0
0.7 = 7.0 » lO'^-l
Since we know the base of the number system, a number
is then represented by its mantissa, 7.0 in the last exam-
ple, and the exponent, here -1. This is called normalized
representation. The factor in front of the exponent is
always a value between 1 and the base of the number system,
or 10 in our case. The calculation rules of mathematics also
apply for these numbers: For example, two normalized
floating-point numbers can be multiplied together by multi-
plying the mantissas and adding the exponents. If the prod-
3
Advanced Machine Language
uct of the mantissas is greater than 10, a factor of ten is
added to the exponent of the product and the mantissa is
adjusted so that it lies in the range 1-10. If we multiply
the last two example numbers together, it looks like this:
5 * lO'^O times 7 * 10^-1
By multiplying the mantissas we get 35; the sum of the
exponents is -1. The result is therefore 35 » lO**-!. This
number must now be normalized since the mantissa is greater
than 10. We get 3.5 * 10^0, or simply 3.5. The normalization
can be thought of simply as moving the decimal point. In our
example, we moved the decimal place one position to the left
and compensated by increasing the exponent by one. When
shifting the decimal place to the right, the exponent must
be correspondingly decremented.
If we want to add our numbers, we know from mathematics
that only numbers with the same exponent can be added. The
exponents must therefore be made equal.
If we make both exponents equivalent to the larger, the
procedure goes like this:
From 7.0 * 10^-1 we get 0.7 * lO'^O. Now we need to add the
mantissas:
5.0 + 0.7 = 5.7 * 10^0
Since the number is already normalized, we have as result
5.7 times 10^0 or simply 5.7.
4
Advanced Machine language
If we want to put this process on a microprocessor, we
must give a bit of thought td how this can best be realized.
The processor can work only with binary nuiobers, so we first
want to convert this procedure to binary numbers.
Let's select 2 as the base of our number system. Before
we can implement floating-point numbers on the microproces-
sor, we should first decide what value range our numbers
will have and to what degree of accuracy the numbers will be
stored. It becomes clear very quickly that, using exponen-
tial representation, the exponent is the key to the value
range, while the mantissa determines to how many places a
number can be represented. He'll return later to the sub-
jects of accuracy and representing decimal numbers in float-
ing point format.
A floating-point number in binary representation has the
following appearance:
1.011101 * 2''10010
or 1.011101 * 2''18
which is
1 * 2-^18 = 262144
+ * 2^17 =
+ 1 * 2'^16 = 65536
+ 1 * 2^15 - 32768
+ 1 * 2''14 = 16384
+ * 2^13 =
+ 1 * 2^12 = 4096
= 380928
5
Advanced Machine Language
Fractional binary numbers can also be used. For example:
1.011 * a'^o
+ 1 * 2^0 = 1
+ * 2'^-! =
+ 1 * 2'^-2 = 0.25
+ 1 * 2^-3 = 0.125
1.375
If, however, we want to represent numbers which are
smaller than one (the exponents of which are therefore less
than zero) we must find a form for representing such expo-
nents. We recall how we have stored negative numbers in the
past. One possibility is two's complement. If we set aside
one byte, 8 bits, for our exponents, we can represent powers
of two from -128 to +127. To find out what decimal range of
values this will allow us to represent, we need only form
the corresponding power of two:
2 ^ 127 = 1.7 * 10^38
2 ^ -128 = 3.9 * 10''-39
Thus if we reserve one byte for the exponent and work with
powers of 2 from -128 to +127, we can work with numbers
which In the decimal system have 38 places before the dec-
imal point or which begin at the 39th place after the dec-
imal point. These numbers then cover the value range which
we are used to in normal calculations in BASIC.
The Commodore 64 does not use two's complement for its
floating-point numbers, but rather an offset. One adds the
6
Advanced Machine Language
number 129 or $81 (hexadecimal) to every exponent and views
the result as a sign-less positive number. This sinplifies
the manipulation of exponents in practice. The following
table gives the assignment of the stored exponent to the
actual power of two. We use the hexadecimal representation
for the sake of simplicity.
Representation
Exponent
Value
$00
see text
$01
-128
3.9 *
10^-40
$02
-127
5.9 *
10''-39
$03
-126
1.2 *
10^^-38
$7F
-2
0.25
$80
-1
0.5
$81
1
$82
1
2
$83
2
4
$FE
125
4.3 *
10''37
$FF
126
8.5 *
10-^37
If the stored value for the exponent is zero, the number is
by convention also zero.
How that we have taken care of the exponents, we can
give some thought to the mantissa.
Since the mantissa determines the number's accuracy, we
must decide how accurately we want to store our numbers. The
Commodore 64 uses 4 bytes for the mantissa. This allows us
to represent 32 binary digits. What sort of accuracy does
this correspond to for decimal numbers?
We compare the decimal values of two binary floating
7
Advanced Machine Language
point numbers which differ only in the last place.
1.111 1111 nil nil nil im im
and
1.111 nil nil nil im im im ^
10
The two numbers are different in the last place, which has a
place value of 2^-31. This is. in decimal, approximately
4.6566129 * lO'^-lO
0.46566129 * 10''-9
The two numbers have a value of somewhat less than 2;
they differ by 5 in the 10th decimal place. We therefore
conclude that we get a decimal accuracy of about 9 places
from a mantissa of 4 bytes. This should suffice for most
applications. The accuracy of 9 places is a relative accu-
racy, independent of the exponent. If we normalize the
decimal numbers so that a digit between 1 and 9 is in front
of the decimal point, we can still represent and differen-
tiate between numbers which differ only in the ninth place
after the decimal.
At this point we can use an exponent between -128 and
+126 as well as mantissa of 4 bytes which allows a decimal
accuracy of 9 places. What we still lack is the ability to
account for the sign of the mantissa. If we are tricky, we
can account for the sign of the mantissa without losing any
8
Advanced Machine Language
accuracy.
Our mantissa will always displayed as normalized, mean-
ing that a digit between one and one less than the base of
the number system will always appear in front of the decimal
point. Using the binary system, the only digit that can
appear is the digit 1. We therefore assume this and do not
save it, but use this bit for the sign. The usual convention
applies, wher^ a "0" indicates a positive number, while a
"1" denotes a negative number.
Now we have all the information we need in order to convert
decimal numbers into binary floating-point format. Let's try
this with some numbers.
1 = 1 * 2-^0
= 1.000 0000 0000 0000 0000 0000 0000 0000 0000 * 2^0
We replace the first 1 in front of the point ("binary
point") with the sign, account for the offset ($81) on the
exponent and get
0000 0000 0000 0000 0000 0000 0000 0000 1000 0001
If we write the exponent first, as is done when storing
floating-point numbers in the computer, we get the following
picture:
1000 0001 0000 0000 0000 0000 0000 0000 0000 0000
9
Advanced Machine Language
To make it easier to read, we convert the number to hexadec
ifflal:
81 00 00 00
This is the representation of the floating-point number 1.0
He will now try to represent the number 10.0. We divide i
into powers of two as follows:
10 = 8 + 2
= 2'"1 + 2'"3
= 1 * 2^3 + * 2'^2 + 1 * 2'^1 + * 2*0
= 1.01 * 2^3 binary
With the exponent and complete mantissa, we get the follow
ing result:
1000 0100 0010 0000 OOOO 0000 0000 0000 0000 0000
or
84 20 00 00 00
We will take a negative number, -5.5
-5.5 = - (4 + 1 + 0.5)
= - (2^2 + 2'^0 + 2^-1)
= - (1 * 2^2 + * 2^*1 + 1 * 2'"0 + 1 * 2^-1)
= - 1.011 * 2'"2 binary
=> 1000 0011 1011 0000 0000 0000 0000 0000 0000 0000
or
10
Advanced Machine Languag«
83 BO 00 00 00
Negative numbers can be easily recognized because the first
byte of the mantissa is always greater than or to equal $80.
With this knowledge we can easily calculate the decimal
value of any floating-point number. If we designate the
individual bytes as follows
EX Ml M2 M3 M4
83 BO 00 00 00
this formula gives us the value:
X = -SGN (Ml AND 128) * 2'^(EX-129) *
(1+ ((Ml AND 127)+(M2+(M3+M4/256)/256)/258)/128)
You can see clearly that the sign is derived from the most
significant bit of the most significant byte of the mantissa
(Ml). The offset of 129 is taken into account on the power
of t**o. The weighting of the individual bytes is taken into
account in the mantissa; subsequent bytes have only one
258th the value of the preceding byte. Let us try out our
formula with the above floating-point number.
X = -SGN (178 AND 128) * 2"(131-129) *
(1+ ((176 AND 127)+(0+(0+0/258)/256)/256)/128)
We get the value -5.5 back again.
Up to now we have had no problems in converting decimal
numbers to binary floating-point numbers. We will now try to
convert the value 0.4.
11
Advanced Machine Language
We proceed systematically and subtract the largest
power of two contained in the number.
0.4 Power of two
-0.25 -2
0.
15
0.
125
0.025
- 0.015625 -6
0.009375
- 0.0078125 -7
0.0015625
- 0.0009765625 -10
0.0005859375
- 0.00048828125 -11
0.00009765625
-0.00006103515625 -14
0.00003662109275 etc.
We can continue this calculation as long as we want to;
the remainder of a division will never be zero. We receive
the periodic value
1. 1001 1001 1001 1001 1001 1001 1001 1001 1001 ... * 2'"-2
12
Advanced Machine Language
We cannot represent the number 0.4 exactly as a binary
floating-point number. We must stop the succession of digits
at the 31st place behind the binary point and then get
1. 1001 1001 1001 1001 1001 1001 1001 100 * 2^-2
In order to increase the accuracy somewhat we will not
truncate the digits, but rather round the number up or down.
Binary values are rounded up when the last (here 32nd) digit
is a 1; the number remains the same for a 0. In our case we
must round up.
1. 1001 1001 1001 1001 1001 1001 1001 101 « 2''-2
If we now take the exponent and sign into account, we get
the following:
0111 1111 0100 1100 11001 1100 1100 1100 1100 1101
or in hexadecimal
7F 4C CC CC CD
The fact that we cannot exactly represent all decimal
numbers with binary floating-point numbers is not just a
defect in base 2, it is a typical phenomenon when converting
from one number system to another. Try to represent the
fraction 1/3 in the decimal system — it cannot be done exact-
ly. The succession of digits
0.33333 33333 33333
must be truncated somewhere. This is not necessary in a
13
Advanced Machine language
number system with base 3, however. We get simply
0.1
which we interpret as 1 « 3^-1 or exactly one third.
Now that we have heard about the fundamentals of float-
ing-point numbers, we want use them. Since a large part of
the built-in BASIC interpreter is concerned with conversion
between various number formats as well as floating-point
arithmetic, it makes sense to learn how to use these rou-
tines .
The BASIC interpreter has two floating-point accumula-
tors, usually shortened to FAC, in which floating-point
numbers are stored. FAC #1 is used for all floating-point
operations. If an operation such as addition requires two
operands, the second is placed in FAC #2. The result is
always returned in FAC #1. Floating-point accumulator #1 is
often designated only as FAC and FAC #2 is then called AHG
(argument). The numbers are not stored in the shortened 5-
byte form in these floating-point accumulators. Instead, an
additional byte is used for the sign. The bit in front of
the binary point which is otherwise replaced by the sign is
then reconstructed. Furthermore, a rounding byte is used in
order to facilitate rounding with various operators. The
floating-point accumulators use the following memory loca-
tions in the zero-page:
14
Advanced Machine Language
FAC
ARG
Exponent
$61
$69
Mantissa 1
$62
$6A
Mantissa 2
$63
$6B
Mantissa 3
$64
$6C
Mantissa 4
$65
$6D
Sign
$66
$6E
Rounding byte
$70
Sign-comparison
byte
$6F
The sign-comparison byte is required for operations
with two operands and is $00 for equivalent signs and $FF
for different signs.
The BASIC interpreter has numerous routines which mani-
pulate floating-point numbers. We will begin with the rou-
tine which reads a decimal number and converts it to a
floating-point number. This routine is used for every number
input. First we will take a brief look at a routine called
"CHRGET" which reads a character from an input line or from
the BASIC program. The routine is located in the zero-page
and has the task of reading a character and executing var-
ious comparisons. The routine has a second entry point by
the name of "CHHGOT" which allows the character last read to
be gotten again.
CHRGET INC TXTPTH
BNE CHRGOT
INC TXTPTH+1
CHRGOT LDA TEXT
CMP #":"
BCS EXIT
CMP #" "
15
Advanced Machine Language
BEQ CHRGET
SEC
SBC *$30
SBC
SBC #$D0
EXIT RTS
The power of this routine and the reason it must be
located in RAM is that it is self-modifying. The address of
TXTPTR, the pointer to the current position froa which the
character will be fetched, is found in the routine itself.
This will be immediately clear if we look at the machine
code for this routine.
0073
E6
7A
INC
$7A
0075
DO
02
BNE
$0079
0077
E6
7B
INC
$7B
0079
AD
02 02
LDA
$0202
007C
C9
3A
CMP
#$3A
007E
BO
10
BCS
$008A
0080
C9
20
CMP
#$20
0082
FO
EF
BEQ
$0073
0084
38
SEC
0085
E9
30
SBC
#$30
0087
38
SEC
0088
E9
DO
SBC
#$D0
008A
80
RTS
When we call the routine CHRGET, the operand of the LDA
instruction at CHRGOT is incremented by one and then the
contents of this memory location are placed into the accumu-
lator. Several comparison instructions follow.
16
Advanced Machine Language
If the ASCII code of the character In the accumulator
is greater than or equal to that for a colon, then control
passes directly to the RTS instruction. In this case, the
carry flag is set. If the character was a colon, the zero
flag is also set. Since the colon denotes the end of a
statement, this can easily be tested for with the zero flag.
If the character's ASCII code is less than that for a colon,
the code is next compared to a apace (ASCII 32). If the test
is positive, control is returned to CHRGET— the next charac-
ter is fetched. Spaces are thereby ignored by the interpre-
ter. The next two subtractions do not change the value in
the accumulator, but they do have an effect on the carry
flag. The carry flag is cleared if the character is an ASCII
digit between "0" and "9", corresponding to $30 and $39.
let's review the points of this routine: the CHHGET
routine increments the text pointer TXTPTR and returns the
current character in the accumulator. If the character is a
colon or a zero byte, which indicates the end of a statement
or the end of the line, respectively, the zero flag is set.
If the character was a digit, the carry flag is cleared.
We now come to our conversion routine. Before we can
call this routine, the accumulator must contain the first
character of the number and the flags must be set according
to the CHRGET routine. The text pointer TXTPTR must natural-
ly point to our number. The following short program reads a
number and converts it into floating point format.
100: 0330 .OPT P,00
105: 033C *= 828
110: 007A TXTPTR = $7A
120: 0079 CHRGOT = $79
17
Advanced Machine Language
130:
BCF3
ASCFLOAT
=
$BCF3
140:
033C
A9
4B
IDA
*<NUMBER
150:
033E
AO
03
LDY
#>NUMBER
160:
0340
85
7A
STA
TXTPTR
170:
0342
84
7B
STY
TXTPTR+1
180:
0344
20
79
00
JSR
CHR60T
190:
0347
20
F3
BC
JSR
ASCFLOAT
200:
034A
00
BRK
210:
034B
31
2E
32
NUMBER
.ASC
"1.2345"
220:
0351
00
.BYT
If we assemble this routine and execute it from the nonitor
with
G 033C
the number 1.2345 Is converted to floating-point format and
placed in FAC #1, which we can see with
N 0061 0066
We get the following values:
>: 0061 81 9E 04 18 93 00
We try our 0.4 again. We must place the digits at address
$034B and terminate them with a zero byte:
M 034B 034B
>: 034B 30 2B 34 00
18
Advanced Machine Language
We get the result
>: 0061 7F CC CC CC CC 00
The sign is saved separately as the sixth byte and is zero
for positive numbers. We can also work with numbers repres-
ented as powers of ten with this number conversion, such as
-1.4E-7 or 1E12. We will take negative number as our next
example, -1E8. Now get
>: 0061 9B BE BC 20 00 FF
This time the negative sign is denoted by $FF.
Let us return briefly to the result of the value 0.4.
We got a value that was one less in the last place than was
the case for the manual conversion. No automatic rounding is
performed by our routine; the rounding byte is used only to
indicate if an overflow is present in the next places. Enter
0.4 again and note the value of the rounding byte at loca-
tion $70. We get $80. This means that the last place of the
result must be incremented by one. There is a routine at our
disposal which does this for us. If we add this to our
program, the converted value is automatically rounded.
100:
033C
.OPT
P.OO
105:
033C
* =
828
110:
007A
TXTPTR
$7A
120:
0079
CHRGOT
$79
130:
BCF3
ASCFLOAT
$BCF3
140:
BCIB
ROUND
$BC1B
150:
033C
A9
48
IDA
*<NUMBER
160:
033E
AO
03
LDY
#>NUMBER
170:
0340
85
7A
STA
TXTPTR
19
Advanced Machine Language
180:
0342 84 7B
STY TXTPTR+1
180:
0344 20 79 00
0347 20 F3 BC
034A 20 IB BC
JSR CHRGOT
200:
JSR ASCFLOAT
210:
JSR ROUND
220:
034D 00
BRK
230:
034E 31 2E 32
NUMBER .ASC "1,2345"
240:
0351 00
.BYT
If we take a look at the FAC, we have the desired result.
>: 0081 7F CC CC CC CD 00
The rounding byte is naturally cleared by rounding, some-
thing of which you can easily convince yourself.
Now that we have converted the digit string to an
internal floating-point number, let's reverse the procedure
by converting a floating-point number back into a string of
decimal digits. This task is performed by the routine
FLOATASC, located at address $BDDD. Calling this routine
converts a number to a string which is placed at address
$0100. Let us try this by writing the following values into
the FAC:
>: 0061 90 8F 00 00 00 80
We take a look at the result after calling the routine:
>M 0100 0107
>: 0100 2D 33 36 36 30 38 00 -36608
The above value in the FAC therefore represents the decimal
number -36608. After calling this routine, the accumulator
20
Advanced Machine Language
and Y register contain the address at which the string was
placed ($100), here A=0 and Y=l (low byte, high byte). Now
we can output the string on the screen. Another routine is
already built into the BASIC interpreter: STHOUT, with ad-
dress $AB1E.
JSR FLOATASC ; convert FAC to ASCII string at $100
LDA #<$100 ; least significant address of string
LDY #>$100 ;most significant address of string
JSR STROUT ; print string pointed to by A,Y
Before we start performing calculations with our float-
ing-point numbers, we first want to become acquainted with
the various BASIC interpreter routines which perform conver-
sions from various whole-number formats to floating-point
format. This is particularly important for our machine lan-
guage programs because all of the arithmetic operations
within the BASIC interpreter are carried out in floating
point, but input and output for these routines often require
or expect numbers in INTEGER format.
21
Advanced Machine. Language
1.2 Conversion to floating-point foraat
1.2.1 Signed one-byte values
The following routine converts a signed one-byte value
into floating-point format. The result will therefore be a
number between -128 and +127. The byte value is passed in
the accumulator.
LDA #BYTE
JSR $BC3C
A value of $80 will be converted to -128, $FF to -1, $7F to
127, and so on.
1.2.2 Unsigned one-byte values
If the sign is not to be taken into account (the byte
is to be treated as unsigned, having a value 0-255), the
following conversion routine must be used:
IDY #BYTE
JSR $B3A2
This routine converts $00 to zero, $80 to 128, and $FF to
265.
1.2.3 Signed two-byte values
A two-byte value with sign can be converted with the
following routine:
22
Advanced Machine Language
LDY *LOH
IDA #HI6H
JSR $B395
The least-signif leant byte nust be placed In the Y register
while the accumulator contains the most-significant byte.
The following examples demonstrate the conversion:
A Y Floating-point value
00
00
00
01
1
00
FF
255
01
00
256
7r
FF
32767
80
00
-32768
FF
FF
-1
1.2.4 Unsigned two-byte values
If the sign of a two-byte value is to be ignored, the fol-
lowing routine is used:
LDY *LOW
LDA #HIGH
STY $63
STA $62
LDX #$90
SEC
JSR $BC49
23
Advanced Machine Language
This conversion assumes that the number is unsigned and
returns values from 0-65535.
A Y Floating-point value
00
00
00
01
1
00
FF
255
01
00
256
7F
FF
32767
80
00
32768
FF
FF
65535
1.2.5 Signed three-byte values
Although three-byte values are rarely used in practice,
the routines for converting such data into floating-point
format should be mentioned.
LOA *LOW
LDX #MID
LDY #HIGH
STY $62
STX $63
STA $64
LDA $62
EOR *$FF
ASL A
LDA *$0
STA $65
LDX #$98
24
Advanced Machine Language
JSR $BC4F
The conversion table looks like this:
Y X A Floating-point value
00 00 00
00 00 FF 255
00 FF FF 65535
7F FF FF 8388607
80 00 00 -8388608
FF FF FF -1
We can cover a value range from -8,388,608 to 8388607 with
3-byte (24-bit) values.
1.2.6 Unsigned three-byte values
If the sign is not to be used, the following routine
can be used.
LDA #LOW
LDX *MID
LDY *HIGH
JSR $AF87
JSR $AF7E
Here we can represent values between and 2'^24-l =
16,777,215.
25
Advanced Nachiiie Language
Y X A Floating-point format
00 00 00
00 00 FF 255
00 FF FF 65535
7F FF FF 8388607
80 00 00 8388608
FF FF FF 16277215
1.2.7 Signed 4-byte values
For the sake of completeness, the conversion of 32-bit
integer values is also presented here. The routines look
similar. Because 4 bytes must be passed, the routine expects
that these values will be stored in the FAC from address $62
(MSB) to $65 (LSB).
LDA $62
EOR #$FF
ASL A
LDA #0
LDX #$A0
JSR $BC4F
We get the following conversion table:
$62 63 64 65 Floating point value
00 00 00 00
00 00 00 FF 255
00 00 FF FF 65535
00 FF FF FF 16777215
7F FF FF FF 2147483647 (2 . 14748365E+09)
80 00 00 00 -2147483648 ( -2 . 14748365E+09)
26
Advanced Machine Language
FF FF FF FF -1
1.2.8 Unsigned 4-byte values
This conversion routine concludes the presentation.
Here too the values must be placed in the FAC.
SBC
IDA #0
LDX #$A0
JSR $BC4F
The value range from to 2^^32-1 = 4,294,967,295 can be
used.
$62
63
64
65
Floating-point
value
00
00
00
00
00
00
00
FF
255
00
00
FF
FF
65535
00
FF
FF
FF
16777215
7F
#f
FF
FF
2147483647
(2.14748365E+09)
80
00
00
00
2147483648
(2.14748365E+09)
FF
FF
FF
FF
4294967295
(4.2949673E+09)
The routines described here are useful if you want to
use one to four-byte values from your own machine language
routines as arguments for the floating-point routines in the
BASIC interpreter. The reverse procedure — converting from
floating-point values to integer numbers — will now be dis-
cussed.
27
Advanced Machine Language
1.3 ConverlBion to integer foraat
Only one routine is required for the conversion froD
floating-point to integer format. The result of this conver-
sion is a signed 4-byte number. If the number to be convert-
ed is in the FAC, the conversion is executed with
JSR $BC9B
Because only numbers which are smaller than 2^31 can be
converted to integer values without error, the exponent of
the number should be checked to see that it is smaller than
$A0, The result of the conversion is stored at $62 (most
significant byte, including sign) to $65 (least-significant
byte). Let us try an example.
The FAC contains the floating-point value 10:
EX Ml M2 M3 M4 SGN
>: 0061 84 AO 00 00 00 00
After the JSR $BC9B we get
>: 0061 84 00 00 00 OA 00
If the FAC does not contain a whole number, the fractional
portion will be truncated as with the INT function. For
example, if the FAC contains 321.25:
EX Ml M2 M3 M4 SGN
>: 0061 89 AO AO 00 00 00
28
Advanced Machine Language
We get the result
>: 0061 89 00 00 01 41 00
or $41 + $100 = 65 + 256 = 321. With negative fractional
numbers, the result will be next-smallest whole number, so
that -0.5 becomes -1.
EX Ml M2 M3 M4 SGN
>: 0061 80 80 00 00 00 FF
We get the result
>:0061 80 FF FF FF FF FF
or -1.
We will later become acquainted with BASIC interpreter
routines which perform range checks before the conversion to
integer format, on the ranges to 255 or -32768 to 32767,
for example.
29
Advanced Machine Language
1.4 BASIC aath routines
Now that we have covered input, output, and conversion
of nufflbers, it is time that we execute the first calcula-
tions.
The interpreter has five basic arithnetic operations,
each having two operands, which are addition, subtraction,
multiplication, division, and exponentiation. If we want to
use these functions, the first operand must be in the FAC
while the second is expected in ARG. After calling the
appropriate routine, the result is left in the FAC. These
are the addresses of the routines:
ADDITION
FAC :
= ARG
+
FAC
$B86A
SUBTRACTION
FAC :
= ARG
FAC
$B853
MULTIPLICATION
FAC :
= ARG
*
FAC
$BA2B
DIVISION
FAC :
= ARG
/
FAC
$BB12
EXPONENTIATION
FAC :
= ARG
FAC
$BF7B
Before calling these routines, the accumulator must
contain the exponent of the number in the FAC ($61). If
this exponent is zero, the number in the FAC is by conven-
tion also zero and special cases can be handled (ARG +0 =
ARG; ARG * = 0; ARG / results in "DIVISION BY ZERO"; ARG
^ yields 1). Now let's multiply two values, such as 7*13 =
91.
7 = 83 ED 00 00 00 00
13 = 84 DO 00 00 00 00
We place the values in the floating-point accumulators, load
the accumulator with the exponent of the FAC, and call the
30
Advanced Machine language
routine.
>: 0061 83 EO 00 00 00 00
>: 0069 84 DO 00 00 00 00
>, 1000 AS 61 IDA $61
>, 1002 20 2B BA JSR $BA2B
>, 1005 00 BRK
>G 1000
B*
PC IRQ SR AC XR YR SP NV-BDIZC
>; 1006 BA31 AO 87 B6 00 F8 10100000
>: 0061 87 B6 00 00 00 00 00
Now we can convert the result into a deciraal number.
1.0110110 * 2*6 = 1011011
= 64 + 16 + 8 + 2 + 1 = 91
Next we will try exponentiation. 3*7 should equal 2187.
3 = 82 CO 00 00 00 00
7 = 8E EO 00 00 00 00
We can pass the values and call the exponentiation routine.
>: 0061 83 EO 00 00 00 00
>: 0069 82 CO 00 00 00 00
31
Advanced Machine language
>,
>.
>,
1000
A5 61
LDA $61
JSR $BF7B
1002
20 7B BF
1005
00
BRK
>G 1000
B*
PC IRQ SR AC XR YR SP NV-BDIZC
>; 1006 EA31 22 00 61 00 F8 10100000
>: 0061 8C 88 BO 00 02 00 00
We get
1.000 1000 1011 0000 0000 0000 0000 0010 * 2''11 =
1000 1000 1011. 0000 0000 0000 0000 0010
= 2^*11 + 2'"7 + 2'"3 + 2'^1 + 2'^0 + 2'^-19
= 2048 + 128 + 8 + 2 + 1 + 1.9*10'^-6
= 2187.0000019
You see that the result is not exact — there is a deviation
in the last two places. Since only 9 significant digits are
displayed when converting from binary to decioal, we receive
from the following instruction
PRINT 3'"7
the result 2187, although the calculation
PRINT 3^7 - 2187
32
Advanced Machine Language
results In
1.90734863E-06
which reveals the discrepancy. If we analyze the routine for
exponentiation in greater detail, we see that the following
algorithm is used:
A B => EXP( B * LOG( A ))
Because the BASIC interpreter can only calculate approxima-
tions for the EXP and LOG functions — as we will see later —
it is no wonder that exponentiation returns a discrepancy.
Since two other functions must be calculated for the expon-
entiation function, this routine is also one of the slowest
arithmetic routines. It requires more than 50 milliseconds
on average. Therefore it is advisable to perform exponentia-
tions with simple, integer exponents with repeated mult-
iplication, both for the sake of speed and accuracy.
3^2 should be calculated as 3 * 3
The multiplication here is more than 20 times faster. A
summary of execution times will be presented later.
So that we can make practical use of our knowledge, we
will first take a look at the way the BASIC interpreter
manages variables. A number of pointers exist in the zero-
page for managing variables. These pointers determine the
areas for the BASIC program, normal variables, indexed var-
iables, and strings. The variable pointers are arranged as
follows.
33
Advanced Machine Language
$2B/$2C
Program
$2D/$2E
Variables
$2F/$30
Arrays
$31/$32
free
$33/$34
strings
$37/$38
BASIC start
program end/variable start
variable end/array start
array end
string start
string end/BASIC RAN end
34
Advanced Machine Language
After turning on the computer, the start of the BASIC
text area is set to $0801 = 2049 and the end to $A000 =
40960. When you enter a program line
10 A=l
the following is allocated:
At the BASIC start $0801 is
- address of the next BASIC line
- line number (LSB, MSB)
- tokenized program line
- $00 signifying the end of this line
From the monitor this looks like:
>N 0800 080F
>: 0800 00 09 08 OA 00 41 B2 31
>: 0808 00 00 00
The program pointers have the following values:
>M 002B 0037
>: 002B 01 08 OB 08 OB 08 OB 08
>: 0033 00 AO 00 00 00 AO
We will try to interpret these contents. At address
($2B/$2C) = $0801 is the address of the next program line in
the format lo/hl, or $0809. Then follows the line number,
also in lo/hi format = $000A = 10. Next is the program text
$41 = "A", $B2 is the interpreter Code for "=", while $31 is
"1" in ASCII code. A zero byte serves to mark the end of the
\
35
Advanced Machine Language
line. The next program line follows the same scheme. But
because we entered only one program line, we find $0000 as
the address of the next program line. By convention this
denotes the end of the program. The address following,
$080B, is stored in ($2D/$2E} and denotes both the end of
the program and the start of the normal variables. Since we
have not defined any variables, the pointers for the variab-
le end and array end have the same value. If we execute the
program with RUK, the variable A is allocated.
>M 0800 0810
>: 0800 00 09 08 OA 00 41 B2 31
>: 0808 00 00 00 41 00 81 00 00
>: 0810 00 00
>M 002B 0037
>: 002B 01 08 OB 08 12 08 12 08
>: 0033 00 AO 00 00 00 AO
Now the start-of-variables pointer ($2D/$2E} points to
$080B and the end-of-variables pointer ($2F/$30) to $0812.
Thus the variable table is $0812 - $080B = $0007 = 7 bytes
long and has the following contents:
>: 080B 41 00 81 00 00 00 00
Variable entries are generally 7 bytes long. The first
two bytes represent the name of the variable, in this case
$41 $00 = A. Variable names which are only one character
long contain a zero as the second character. Following the
name is the floating point representation of the value in
the abbreviated 5-byte form in which the sign is the first
bit of the mantissa. The value 81 00 00 00 00 has a decimal
36
Advanced Machine Language
equivalent of 1.
We will now take a look at what happens when we use
Integer variables. We change our program line to
10 A«=l
>M 002B 0037
>: 002B 01 08 OC 08 13 08 13 08
>: 0033 00 AO 00 00 00 AO
>M 0800 0810
>: 0800 00 OA 08 OA 00 41 25 B2
>: 0808 31 00 00 00 CI 80 00 01
>: 0810 00 00 00
The program has become one byte longer because of the
percent sign. The variable entry is still 7 bytes long. Do
recognize the name A or A% in the table? If you compare the
bit pattern $C1 $80 with $41 $00, you see that the most
significant bit (bit 7) of both bytes is set. This is how
integer variables are denoted. The next two bytes contain
the 18-bit integer value $0001, in which the most-signifi-
cant byte comes first. The next three bytes are unused for
integer variables. Therefore when you work with normal int-
eger variables, there is no space savings. Using integer
variables does not increase the speed either — in fact, just
the opposite since all of the math operations are performed
in floating-point arithmetic and that additional conversion
are necessary.
Let us move on to the string variables. Enter the
following program line:
37
Advanced Machine .Language
10 A$="STHING"
HUN the program and take a look at the result with a
Bonitor .
>M 002B 0037
>: 002B 01 08 13 08 lA 08 lA 08
>: 0033 00 AO 00 00 00 AO
>M 0800 0810
>: 0800 00 11 08 OA 00 41 24 B2
>: 0808 22 53 54 52 49 4E 47 22
>: 0810 00 00 00 41 80 06 09 08
>: 0818 00 00
If you take a look at the pointer for the string area, you
see that nothing has been altered. The variable table begins
at $0813 and looks like this:
>: 0813 41 80 06 09 08 00 00
The first two bytes again represent the name of the
variable. You have probably already noticed that the most
significant bit of the second byte of the variable name is
set in order to denote a string variable— $41 $00 becomes
$41 $80. The next three values can be interpreted as fol-
lows: The first value, $06, gives the length of the string:
6 characters. The next two bytes point to the address at
which the string can be found: $0809. Thus they point to an
area within the program, directly behind the first quotation
mark. This is also the reason that the string area is still
empty. The situation changes if we modify the string, how-
38
Advanced Machine Language
ever, as we see in the next example:
10 A$="STHING"
20 A$=LEFT$(A$.3)
>M 002B 0037
>:
002B
01
08
22
08
29
08
29
08
>:
0033
FD
9P
00
AO
00
AO
>N
0800
0810
>:
0800
00
11
08
OA
00
41
24
B2
>:
0808
22
53
54
52
49
4E
47
22
>:
0810
00
20
08
14
00
41
24
B2
>:
0818
C8
28
41
24
2C
33
29
00
>:
0820
00
00
41
80
03
FD
9F
00
>:
0828
00
The variable
table begins
at
$01
>:
0822
41
80
03
FD
9F
00
00
Following the variable nane is the length (3 this time) and
the address of the string, $gFFD, which is also the lower
boundary of the string storage. If we look there, we find
our new string "STR".
>: 9FFD 53 54 52
How are variable arrays organized? Erase the current program
(with NEW) and enter the following:
10 DIN A(500)
RUN
39
Advanced Machine Language
We get the following storage allocation:
>M 002B 0037
>: 002B 01 08 10 08 10 08 EO 11
>: 0033 00 AO 00 00 00 AO
Since no non-array variables are defined, the starting and
ending pointers have the same value. $0810. This is also the
start of the array area. The array area extends to $11B0,
and is therefore $11E0 - $0810 = $09D0 = 2512 bytes long!
The start looks like this:
>M 0810 0820
>: 0810 41 00 DO 09 01 01 F5 00
>: 0818 00 00 00 00 00 00 00 00
>: 0820 00 00 00 00 00 00 00 00
The name of the array is encoded in the first two
bytes. The following two bytes contain the length of the
memory occupied by the array. $09D0. which we calculated
above. The next "01" indicates that the array has one dimen-
sion,
Next is the number of array elements, $01F5 = 501.
There are five hundred and one because an element exists
with the index 0, A(0). Finally. the values of the array
elements are stored starting with the zero element. If we
enter A(0) =10 : A(l) =11 i„ the direct mode, the representation
appears as follows:
>M 0810 0820
>: 0810 41 DO DO 09 01 01 F5 84
>: 0818 20 00 00 00 84 30 00 00
>: 0820 00 00 00 00 00 00 00 00
40
Advanced Machine Language
84 20 00 00 00 => 10; 84 30 00 00 00 => 11
Now let's see how Bulti-dimensional arrays are stored.
Enter
DIM B(l,2,3)
in the direct mode. The array table starts at $0803 and
looks like this:
>M 002B 0037
>: 002B 01 08 03 08 03 08 86 08
>: 0033 00 AO 00 00 00 AO
>M 0803 0813
>: 0803 42 00 83 00 03 00 04 00
>: 080B 03 00 02 00 00 00 00 00
>: 0813 00 00 00 00 00 00 00 00
We recognize the name "B" ($42). The length of the
array table is $0083 = 131 bytes this time. Then comes a 3
which indicates that the array is three-dimensional. Next
are the index boundaries, beginning with the last index
$0004, then $0003, and $0002 corresponding to 3, 2, and 1.
How are these values allocated? This is the order in which
the individual array elements are stored:
B(0,0,0)
B(1,0,0)
B(0,1,0)
Bd.l.O)
B(0,2,0)
B(l,2,0)
41
Advanced Hachine Language
B(0,0,1)
8(1,0,1)
8(0,1,1)
8(1,1,1)
8(0,2,1)
8(1,2,1)
8(0,0,2)
8(1,0,2)
8(0,1,2)
8(1,1,2)
8(0,2,2)
8(1,2,2)
8(0,0,3)
8(1,0,3)
8(0,1,3)
8(1,1,3)
8(0,2,3)
8(1,2,3)
If we use arrays with integer variables. only 2 bytes
are reserved for each array element, resulting in a space
savings compared to floating point arrays. Only three bytes
per element are used for string arrays. The first byte
represents the length of the individual string element and
the next two bytes give the actual memory address of the
string. No space is used for the strings themselves until
they are actually assigned values. Using this information we
can state the space requirements of any array:
M = 5 + 2*N + T ♦ PHOD(Ni+l)
M is the required memory space of the entire array, N is the
number of dimensions, T is the specified space requirement
42
Advanced Machine Language
per element (2 for integer, 5 for real, and 3 for string)
and PHOD(Ni+l) the product of the index boundaries +1.
The following examples should clarify the formula:
The constant 5 is based on 2 bytes for the name, 2
bytes for the length, and one byte for the number of dimen-
sions. Two bytes are required for each dimension for the
index boundaries. The space for the elements themselves is
contained in the last term. Let's try our formula for the
first array A(500) .
P = 5 + 2*1 + 5*{501)
P = 2512 bytes
Our three dimensional array B(l,2,3) requires the following
space in memory:
p = 5 + 2*3 + 5*(2*3*4)
P = 131 bytes
The array AX(10,10,10) requires the following memory space:
p = 5 + 2*3 + 2*{11*11*11)
P = 2673 bytes
A string array A$(100,100) would hardly fit into memory.
P = 5 + 2*2 + 3*(101*101)
P = 30603 bytes
The array table alone requires 30K bytes; there are
only 8K bytes left for the 10201 elements.
43
Advanced Machine Language
1.5 BASIC floating-point routines
Now that we know how to execute the fundamental float-
ing-point calculations in BASIC, it is time to look at the
functions .
A function can be written in general as
Y = F(X)
in which X is the argument, F is the function, and Y is the
result. The floating point functions are written such that
the argument X must be placed in the FAC before the function
can be called. The result of the function call is placed
back into the FAC.
The BASIC interpreter contains a number of useful func-
tions which we can use:
Name
Address
Calculation time
Description
ABS
$BC58
0.0 ms
absolute value
ATN
$E30E
44.6 ms
arctangent
COS
$E264
27.9 ms
cosine
EXP
$BFED
26.6 ms
power of e
FRE
$B37D
0.6 ms
free memory space
INT
$BCCC
0.9 ms
greatest-int function
LOG
$B9EA
22.2 ms
natural logarithm
PCS
$B39E
0.3 ms
cursor column
RND
$E097
3.5 as
random number
SGN
$BC39
0.4 ms
sign
SIN
$E26B
24.5 ms
sine
SQR
$BF71
51.2 ms
square root
TAN
$E2B4
49.8 ms
tangent
44
Advanced Machine Lan{(uage
The calculation times were obtained using pi as the
argument. As you can see from the table, the vary enormous-
ly. Above all, the so-called transcendental functions such
as COS, EXP, LOG, SIN, TAN, and ATN require a relatively
large amount of time. These functions cannot be calculated
exactly using the four basic math operators. Most functions
are approximated using polynomials, which are functions of
the form
y = ao + ai*x + a2*x2 + aa^x^ + a4 ^x^ + a4*x5 + ...
The more terms such an expression has, the more exact the
result will be, but the longer the calculation will take.
If one wants to calculate a polynomial, such as a 5th
degree polynomial
1+2+3+4+5= 15 multiplications
and 5 additions would be necessary.
There is a different method of solution which goes under the
name "Horner Scheme" (polynomial substitution). The above
equation can be reworked as follows:
y = ((((as *x + a4) *x + a3) *x + a2) *x + ai) *x + ao
Here only 5 multiplications and 5 additions are neces-
sary. In general, a polynonial of degree n requires n mult-
iplications and n additions compared to n*(n-l)/2 multipli-
cations and n additions.
The simplicity of this procedure can be demonstrated
45
Advanced Machine language
with a sinple BASIC program.
100 Y = A(N)
110 FOR I = N-1 TO STEP -1
120 Y = y * X + A(I)
130 NEXT
The program calculates the value of a polynomial of nth
degree for the value x and returns the result in y. The
array A(0) to A(N) contains the coefficients aO through aN.
This routine for polynomial evaluation is the heart of
all of the transcendental functions which the BASIC inter-
preter must calculate.
To use this routine, the argument of the polynomial
must be in the FAC . The polynomial coefficients must be in
the following format in the memory:
polynomial degree n
coefficient of nth degree
coefficient of (n-l)th degree
coefficient of 1st degree
coefficient of 0th degree
The degree of the polynomial is stored as a one-byte
value, which must follow the coefficients as a 5-byte float-
ing-point value. The address of this coefficient field must
be passed when the routine is called. The low byte must be
in the accumulator and the high byte in the Y register. With
this knowledge we can write a routine to calculate polyno-
mials.
46
Advanced Machine Language
It is relatively complicated to place floating-point
values into object code with a normal assembler. We can
assign the value to a variable, use a monitor to find the
variable table, note the corresponding 5 bytes of the var-
iable value and then insert this into the source text with
the .BYT command. ASSEMBLBR/MONITOH 64 allows you to insert
floating-point constants directly into the source. This is
done with the . FLP pseudo-op (Floating Point). The assembler
then performs the conversion into the internal 5-byte rep-
resentation.
Let us put our knowledge into practice and calculate the
following polynomial:
y = 0.7 + 2.5 * X + 8.2 * x2 - 2.3 * x3 + 0.5 * x«
ASSEMBLER 64 V2.0 PAGE 1
100:
033C
.OPT P.OO
110:
120:
; POLYNOMIAL CALCULATION
130:
140:
033C
t= 828 ;
CASSETTE BUFFER
150:
1
160:
E059
POLYNOM
$E059
170:
1
180:
033C
A9
43
LDA #< COEFF
190:
033E
AO
03
LDY #> COEFF
200:
0340
4C
59
EO
JMP POLYNOM
210:
220:
0343
04
COEFF
.BYT 4 ;
DEGREE OF POLY.
230:
0344
80
00
00
.FLP 0.5 ;
A(4)
47
Advanced Machine language
240: 0349 82 93 33
250: 034E 84 03 33
260: 0353 82 20 00
270: 0358 80 33 33
280:
]033C-035D
NO ERRORS
The entire routine consists of passing the starting
address and calling the polynomial function; the coeffi-
cients of the polynomial then follow in decreasing order.
How can we use our new function? It obviously won't
work well with the SYS coiiiniand~how are we supposed to pass
the paraffleters and get the function value back? We need a
function similar to the built-in functions like SIN, BXP,
and so on.
The interpreter has already taken this case into con-
sideration. It offers the USH function which you can freely
define. We need only inform the interpreter of the starting
address of the function. This starting address is placed in
the usual form, low/high byte, at the addresses 785/786
($0311/$0312) .
POKE 785,828AND255 : POKE 786,828/256
Now enter the following, after the program has been assem-
bled and the above line typed in:
? USR(l)
Vou get the value 9.6. A check of the formula confirms the
.FLP -2.3 ; A(3)
.FLP 8.2 ; A(2)
.FLP 2.5 ; A(l)
.FLP 0.7 ; A(0)
48
Advanced Machine Language
correctness of the result.
y = 0.7 + 2.5 + 8.2 - 2.3 + 0.5 = 9.6
The following loop can be added for additional checks.
FOR I=-5 TO 5 : PRINT USR(I) : NEXT
793.2
397.1
169.6
54.9
9.2
.7
9.6
28.1
60.4
122.7
243.2
This method for calculating polynomials is recommended
whenever a program must repeatedly calculate the same poly-
nomial. The execution time of this function at 12.5 ms is
even shorter than many built-in functions. The calculation
in BASIC requires about 45 ms. The more complicated the
formula is, the faster the machine language version will run
in comparison.
As you can gather from the above example, the coeffi-
cients, including their signs, must be in descending order
(meaning that the coefficient of the highest power of x is
first). If a power of x is missing in the polynomial, a zero
must be inserted as its value.
49
Advanced Machine Language
The next example will calculate the factorial function.
Factorial is a function which is first defined only for
positive integer values and which consists of the product of
all integers from one to the given number. For example
5! =1*2*3*4*5= 120
or
7! =1*2*3*4*5*6*7= 5040
In mathematics, the function is also extended to include
non-integers, which can again be approximated through a
polynomial. This polynomial is only defined for values bet-
ween zero and one, however; function values of other argu-
ments must be counted backwards. For example:
4.3! = 4.3 * 3.3 * 2.3 * 1.3 * 0.3!
The factorial of 0.3 can be calculated with an eighth degree
polynomial having the following coefficients:
ao = 1
ai = -.57719 1652
az = .98820 6891
aa = -.89705 6937
a4 = .91820 6857
as = -.75670 4078
as = .48219 9394
87 = -.19352 7818
aa = .03586 8343
50
Advanced Machine Language
We can now write a program to calculate this polynonial.
ASSEMBLER 64 V2.0 PAGE 1
100:
033C
.OPT
PI, 00
110:
120:
; POLYNOMIAL FOR FACTORIAL CALCULATION
130:
1
140:
033C
*=
828 ; CASSETTE BUFFER
150:
f
160:
E059
POLYNOM
$E059
170:
*
180:
033C
A9
43
LDA #< COEFF
190:
033B
AO
03
LDY #> COEFF
200:
0340
4C
59
EO
JMP POLYNOM
210:
1
220:
0343
08
COEFF
• BYT
8 ;8TH DEGREE POLY.
230:
0344
7C
12
EA
.FLP
.035868343
240:
0349
7E
C6
2C
.FLP
-.193527818
250:
034E
7F
76
E2
.FLP
.482199394
260:
0353
80
CI
B7
.FLP
-.756704078
270:
0358
80
6B
OF
.FLP
.918206857
280:
035D
80
E5
A5
.FLP
-.897056937
290:
0362
80
7C
FB
.FLP
.988206891
300:
0367
80
93
C2
.FLP
-.577191652
310:
036C
81
00
00
.FLP
1
]033C
-0371
NO ERRORS
We can calculate the factorial values for arguments between
and 1 with PRINT USR(X). For example:
51
Advanced Machine Language
?USR(.l) => 0.951350564
?USR(.5) => 0.886227246
We can also calculate the factorial values for numbers
outside of this range with a small BASIC routine.
10 INPUT "ARGUMENT"; X
20 IF X<0 OR X>33 THEN 10
30 IF X=0 THEN Y=l : GOTO 70
40 Y=X : IF X<1 THEN Y = USH(X) : GOTO 70
50 X=X-1 : IF X>1 THEN Y=Y*X : GOTO 50
60 IF XOl THEN Y = Y * USH (X)
70 PRINT "FACTORIAL =";Y
Line 20 prevents negative values from being entered as
well as values which have a factorial greater then 1E38. The
argument returns 1 by definition (line 30). In line 50 the
argument is multiplied by the running product and decrement-
ed by one until it is less than or equal to one. A check is
made in line 60 to determine if the argument is an integer.
If this is not the case, the polynomial value must yet be
multiplied by the result. Finally, the result is printed in
line 70. For example:
=> 1
1 => 1
1.5 => 1.32934087
2 => 2
3 => 6
0.5 => .886227246
7.35 => 10287.3151
52
Advanced Machine Language
Now that we have calculated the polynomial with a
machine language routine of our own, we want to try to
replace the entire BASIC program with a machine language
program. By so doing we will become acquainted with more of
the floating-point arithmetic routines. On the next page is
a flow chart of the program operation.
53
Advanced Machine ianguage
54
Advanced Machine Language
Let's try our new function out. (Do not forget to first set
the USR vector at address 785/786 to our routine — after
turning the conputer on this vector always points to "IL-
LEGAL QUANTITY").
?USH(0)
= >
1
?USH(1)
= >
1
?USR(2)
= >
2
?USR(3)
= >
6
?USR( .5)
= >
.886227246
?USR{4.5)'
= >
52.3427967
?USR(-1)
= >
ILLEGAL QUANTITY
?USR(40)
= >
OVERFLOW ERROR
What we had to do with a relatively complicated BASIC
program before can now be done quickly and easily, simply by
calling a function. We used some new routines in the machine
language program which we want to discuss briefly.
FACNBM - This routine stores the contents of the floating
point accumulator FAC at the address given in the X (low
byte) and Y (high byte) register. The contents of the FAC
are stored in the abbreviated 5-byte form.
NEMFAC - performs the opposite task. It gets a floating
point number from memory and puts it in the FAC. This time
the A register must contain the low byte of the address and
the Y register the high byte.
COMPARE - We can compare two floating-point numbers to each
other with this BASIC interpreter routine. The first number
is in memory and is addressed through A (low byte) and Y
(high byte). The second number must be in the FAC. If both
55
Advanced Machine Language
numbers are the sane, the accumulator (not the floating-
point accumulator!) contains a zero and the Z flag is set.
If the first value is smaller than the number in the FAC,
the accumulator contains -1 ($FF} and the N flag is set. If
the number in the FAC was smaller, the accumulator contains
1 and the N flag is cleared. This routine was used exten-
sively in our program.
MEMPHIS - This routine consists of two subroutines. First
the floating-point number pointed to by A and Y (low/high)
is placed in ARG and then the routine for adding the FAC and
ARG is called, which leaves the result in the FAC.
MEMNULT - This routine serves to multiply a number in memory
with the FAC. The logic corresponds to that of MBMPLUS.
The addresses OVERFLOW and ILLQUAN call the appropriate
routines for outputtlng error messages. It was unnecessary
to check to see if the argument was greater than 34 in our
case because this error message would automatically appear
in the course of the multiplications.
The function for polynomial calculation can be put into
yet another form.
y = ao * X + ai * x3 + az * x5 + as * x'' + . . .
This function is derived from the normal polynomial calcula-
tion by taking x^ as the argument and multiplying the result
by X once again.
y = x * ( ao + ai * (x^) + az * (x2)2 +83 * (x2)3 + ... )
56
Advanced Machine Language
This routine is used for most built-in functions because the
approxiination polynomial is often in this form. The argument
must usually first be brought into a specific value range
for which the function is defined and then the result is
modified corresponding to the original value.
We will calculate the following formula with this routine:
y = 6*x + 0.5*x3+-0.11*x''
Note that a term is missing from the sequence (that with
exponent 5), which we must replace with zero as the coeffi-
cient.
ASSEMBLER 64 V2.0 PAGE 1
100:
033C
.OPT P.OO
110:
033C
*= 828
120:
1
130:
E043
P0LY2
$E043
140:
t
150:
033C
A9
43
L0A #< COEFF
160:
033E
AO
03
LDY #> COEFF
170:
0340
4C
43
EO
JMP P0LY2
180:
1
190:
0343
03
COEFF
.BYT 3 ;
200:
0344
7D
El
47
.FLP -.11
210:
0349
00
00
00
.FLP
220:
034E
80
00
00
.FLP .5
230:
0353
83
40
00
.FLP 6
]033C
-0358
NO ERRORS
DEGREE OF POLY.
57
Advanced Machine Language
Note that here the degree of the polynomial comes from
the number of the highest power, not the highest power,
because we have taken x out of the parentheses and use x2 as
the argument.
Here are a few function values for a check:
USR(O) =
USR(l) = 6.39
USR(2) = 1.92
USR(.75) = 4.69625427
At the close of our discussion of floating-point num-
bers we want to take up a problem which occurs often in
programming: sorting number arrays. We will try to implement
the following algorithm in machine language.
100 FOR 1=1 TO N : FL=0
110 FOR J=N TO I STEP -1
120 IF A(J-1)>A{J) THEN H=A( J) : A( J) =A( J-1 ) : A( J-1 ) =H: FL=1
130 NEXT J
140 IF FL=0 THEN RETURN
150 NEXT I: RETURN
The program sorts the array A(N) and can be called as a
subroutine with GOSUB 100. The program uses a bubble-sort
algorithm. Two successive array elements are compared with
each other. If the first element is greater than the second,
the two elements are exchanged and a flag is set. This
occurs in two nested loops. If no exchange occurs during the
course of the inner loop, the array is sorted. In this case
the flag remains zero and the sorting process ends prema-
turely. Otherwise, the smallest value will be found in A(0)
58
Advanced Machine Language
after the first pass. The next pass compares elements 1
through N, then 2 through N, and so on. Do you remember how
BASIC array elements are stored? There is a pointer which
indicates the start of the array table. So that we do not
have to search through this table to find the right array,
we will agree that the array to sorted must have only one
dimension and that it must also be the first array in the
table.
100: 033C
110: 002F ARRTAB
120: 0057
130: 0057 IPNT
140: 0059 JPNT
150: 005B JPNTl
160: ;
170: BBA2 MBNFAC
180; BC5B COMPARE
190: ;
200: 033C
210: ;
220: 033C AS 2F
230: 033E 18
240: 033F AO 02
250: 0341 71 2F
260: 0343 8D 09 03
270: 0346 C8
.OPT PI
$2F
*= $57
*= »+2
*= *+2
*= *+2
$BBA2
$BC5B
*= 828
LDA ARRTAB
CLC
LOY *2
ADC ( ARRTAB ),Y ; ADD ARRAY
LENGTH
STA NPNT ; POINTER N TO
ARRAY END
INY
59
Advanced Machine Language
280:
0347
A5
30
LDA
ARRTAB-t-l
290:
0349
71
2F
ADC
(ARRTAB) ,Y
300:
034B
8D
DA
03
STA
NPNT+1
310:
034E
AD
D9
03
LDA
NPNT
320:
0351
38
SEC
330:
0352
E9
05
SBC
#5
340:
0354
80
D9
03
STA
NPNT
350:
0357
BO
03
BCS
LI
360:
0359
CB
DA
03
DEC
NPNT+1
370:
t
380:
035C
A5
2F
LI
LDA
ARRTAB
390:
035E
18
CLC
400:
035F
69
07
ADC
#7
410:
0361
85
57
STA
IPNT ; POINTER
A(0)
420:
0363
A5
30
LDA
ARRTAB+1
430:
0365
69
00
ADC
#0
440:
0367
85
58
STA
IPNT+1
450:
f
460:
0369
AO
00
ILOOP
LDY
#0
470:
036B
8C
D8
03
STY
FLAG ; CLEAR FLi
480:
036E
AD
D9
03
LDA
NPNT
490:
0371
85
59
STA
JPNT ;J=N
500:
0373
AD
DA
03
LDA
NPNT+1
510:
0376
85
5A
STA
JPNT+1
520:
530:
0378
A5
59
JLOOP
LDA
JPNT
540:
037A
38
SEC
550:
037B
E9
05
SBC
#5
60
Advanced Machine Language
560:
037D
85
58
STA
JPNTl ;
POINTER J-1
570:
037F
AA
TAX
580:
0380
A5
5A
LDA
JPNT+1
590:
0382
E9
00
SBC
*0
600:
0384
85
5C
STA
JPNTl+1
610:
0386
A8
TAY
620:
0387
8A
TXA
630:
0388
20
A2
88
JSR
MEHFAC ;
A(J-l) TO FAC
640:
1
650:
038B
A5
59
LDA
JPNT
660:
038D
A4
5A
LDY
JPNT+1
670:
038F
20
58
8C
JSR
COMPARE
; COMPARE TO A(J)
680:
0392
30
12
BHI
NOSWAP
690:
f
700:
0394
AO
04
LDY
#4
705:
0396
8C
D8
03
STY
FLAG ;
SET FLAG
710:
0399
81
59
SWAP
LDA
(JPNT) , Y
720:
039B
AA
TAX
730:
039C
81
58
LDA
(JPNTl) ,Y
740:
osgE
91
59
STA
(JPNT) , Y
; EXCHANGE A(J)
750:
03A0
8A
TXA
t
AND A(J-l)
760:
03A1
91
SB
STA
(JPNTl) ,Y
770:
03A3
88
DEY
780:
03A4
10
F3
BPL
SWAP
790:
1
800:
03A6
A5
59
NOSWAP
LDA
JPNT
810:
03A8
38
SEC
820:
03A9
E9
05
SBC
#5
825:
03AB
85
59
STA
JPNT
61
Advanced Machine Language
830:
03AD
BO
02
BCS
TESTJ
840:
03AF
C6
SA
DEC
JPNT+1
850:
f
860:
03B1
C5
57
TESTJ
CMP
IPNT
870:
03B3
DO
C3
BNE
JLOOP
880:
03B5
AS
SA
LDA
JPNT+1
890:
03B7
C5
58
CMP
IPNT+1
900:
03B9
DO
BD
BNE
JLOOP
910:
920:
03BB
AD
D8
03
LDA
FLAG
930:
03BE
FO
17
BEQ
END
940:
s
950:
03C0
AS
57
LDA
IPNT
960:
03C2
18
CLC
970:
03C3
69
05
ADC
#5
980:
03C5
85
57
STA
IPNT
990:
03C7
90
02
BCC
TESTI
1000:
03C9
E6
58
INC
IPNT+1
1010:
t
1020:
03CB
CD
D9
03
TESTI
CMP
NPNT
1030:
03CB
DO
99
BNE
I LOOP
1040:
03D0
AS
58
LDA
IPNT+1
1050:
03D2
CD
DA
03
CMP
NPNT+1
1060:
03D5
DO
92
BNE
I LOOP
1070:
»
1080:
03D7
60
END
RTS
1090:
f
1100:
03D8
FLAG
* =
*+l
1110:
03D9
NPNT
* =
«+2
]033C
-03DB
NO ERRORS
;N0 EXCHANGES?
! 1=1+1
; I=N?
62
Advanced Machine Language
Advanced Machine Language
This assembly language program takes over the task of
the previous BASIC program. As said before, the array to be
sorted must be one-dimensional. The program does not check
to see if the array is allocated or if it is one dimen-
sional — that is the responsibility of the user.
To sort an array, all that is required is to call the
routine with
SYS 828
In order to get an idea of the speed of the program, we
filled various large arrays with random numbers and first
sorted them with BASIC and then with machine language. The
results are found in the following table.
N BASIC Machine lang. routine
10 1" 0.0"
50 24" 0.4"
100 1' 37" 1.5"
200 6' 33" 6.3"
500 41* 38.7"
1000 2h 44' 2' 33.4"
You can see from the table that approximately four
times as much time is required for twice as many elements to
be sorted. If you must sort large arrays in BASIC, there
comes a point at which the time requirement enters the hours
range. Here our machine language is a good sixty times
faster. If you have very large arrays and the machine lan-
guage routine still takes too long for you, you must use a
more efficient routine such as quicksort.
64
Advanced Machine Language
As an exercise, you might like to try to modify our
routine so that It can sort Integer arrays. What must be
changed? For one, the different space requirement of an
element must be taken Into account — 2 bytes must be added or
subtracted as necessary Instead of 5 bytes. For another, we
should perform the comparison of the elements ourselves. We
can compare the two-byte values directly Instead of convert-
ing the integers to floating-point and then executing the
floating-point comparison. In addition, the routine will be
faster than the floating-point sort routine.
As a reference for your own applications, we present a
table of all of the functions and operations of the BASIC
interpreter which pertain to arithmetic.
Name
Address
Pointer to
constants
Preparat ion
FAC
Function
MEMARG
$BA8C
A/Y
ARG
: = constant
FACARG
$BBFC
+
FAC
:= ARG
DIV
$BB12
A = EXP
+
FAC
: = ARG/FAC
MEND IV
$BBOF
A/Y
+
FAC
:= cons/FAC
TINEIO
$BAE2
+
FAC
:= FAC*10
DIVIO
$BAFE
+
FAC
:= FAC/10
PLUS05
$B849
FAC
: = FAC+0.5
MENFAC
$BBA2
A/Y
+
FAC
:= constant
FACARG
$BCOC
ARG
: = FAC
FACMEM
$BBD4
X/Y
cons
tant := FAC
MINUS
$8853
A = EXP
+
FAC
: = ARG-FAC
MEMMIN
$B850
A/Y
+
FAC
: = cons/FAC
MULT
$BA2B
A = EXP
+
FAC
:= AHG*FAC
MEMMUL
$BA28
A/Y
+
FAC
:= cons*FAC
65
Advanced Machine Language
PLUS
$B86A
-
A = EXP
+
FAC : = ARG+FAC
MBMPLU
$B867
A/Y
..- ■
+
FAC : = cons-t-FAC
POWER
$BF7B
-
A = EXP
+
FAC := AHG^FAC
PWRMEM
$BF78
A/Y
-
+
FAC : = ARG^cons
POLY
$B059
A/Y
-
+
FAC := polynom.
P0LY2
$B043
A/Y
-
+
FAC := polynoB2
OR
$AFB6
-
-
+
FAC:=ARG OR FAC
AND
$AFB9
+
FAC:=AHG AND FAC
NOT
$AED4
+
FAC := NOT FAC
COMPAR
$BC5B
A/Y
comp FAC w/ cons
ROUND
$BC1B
+
round FAC
CHGSGN
$BFB4
+
FAC := -FAC
Conversions and standard functions are not listed since
they were detailed in other places.
The "+" in the FAC colunn indicates that the contents
of the FAC are changed; a "-"indicates that they remain the
sane. If an operation uses both the ARG and FAC, the accumu-
lator should be loaded with the exponent of the FAC ($61)
before the call.
With the logical operations AND, OR, and NOT the argu-
ments are first converted to 16-bit integers, then the
operation is executed bitwise, the result converted back to
a floating-point number and placed back into the FAC.
The BASIC interpreter contains a number of floating
point numbers which you can use for your own applications.
They are listed in the following table.
66
Address
Constant
Advanced Machine Language
Decimal value Significance
$AEA8
82
49
OF
DA
Al
$B1A5
90
80
00
00
00
$B9BC
81
00
00
00
00
$B9C2
7F
5E
56
CB
79
$B9C7
80
13
9B
OB
64
$B9CC
80
76
38
93
16
$B9D1
82
38
AA
3B
20
$B9D6
80
35
04
F3
34
$B9DB
81
35
04
F3
34
$B9E0
80
80
00
00
00
$B9E5
80
31
72
17
F8
$BAF9
84
20
00
00
00
$BpB3
9B
3E
BC
IF
FD
$BDB8
9E
6E
6B
27
FD
$BDBD
9E
6E
6B
28
00
$BFBF
81
38
AA
3B
29
$BFCS
71
34
58
3E
56
$BFCA
74
16
7E
B3
IB
$BFCF
77
2F
EE
E3
85
$BFD4
7A
ID
84
IC
2A
$BFD9
7C
63
59
58
OA
$BFOE
7B
75
FD
E7
C6
$BFE3
80
31
72
18
10
$BFE8
81
00
00
00
00
$E08D
98
35
44
7A
00
$E092
68
28
Bl
46
00
$E2E0
81
49
OF
DA
A2
$E2E5
83
49
OF
DA
A2
$E2BA
7F
00
00
00
DO
$E2F0
84
E6
lA
2D
IB
$E2F5
86
28
07
FB
F8
3.14159265 PI
-32768
1
.434255942
.576584541
.961800759
2.88539007
.707106781 1/SQR(2)
1.41421356 SQR(2)
-.5
.693147181 L0G(2)
10
99999999.9
999999999
1B9
1.44269504 1/1.06(2)
2.14987637E-5
1.4352314E-4
1.34226348E-3
9.614011701E-3
.0555051269
.240226385
.693147186
1
11879546
3.92767774E-4
1.57079633 PI / 2
6.28318531 PI * 2
.25
-14.3813907
42.0077971
67
Advanced Machine Language
$E2FA
87
99
68
89
01
$E2FF
87
23
35
DF
El
$E304
86
A5
5D
E7
28
$E309
83
49
OF
DA
A2
$E33F
76
B3
83
BD
D3
$E344
79
IE
F4
A6
F5
$E349
7B
83
FC
BO
10
$E34E
7C
OC
IF
67
CA
$E353
7C
DE
53
CB
CI
$E358
7D
14
64
70
4C
$E35D
7D
B7
EA
51
7A
$E362
7D
63
30
88
7E
$E367
7E
92
44
99
3A
$E36C
7E
4C
CC
91
C7
$E371
7F
AA
AA
AA
13
$E376
81
00
00
00
00
-76.7041703
81.6052237
-41.3147021
6.28318531 PI « 2
-6.84793912E-4
4.85094216E-3
-.0161117016
.034209638
-.054279133
.0724571965
-.0898019185
.110932413
-.142839808
. 19999912
-.33333316
1
68
Advanced Machine Language
SECTION 2 Interrupts
2.1 Interrupt programing
One area avoided by nany machine language programmers
is the programming of interrupts. We want to demonstrate the
principles and prove that any fear of this subject is comp-
letely unfounded. We will explain what an interrupt is and
what possibilities are opened up to the machine language
programmer by using such new techniques.
First we must explain what we mean by the term "inter-
rupted." What is interrupted, and how? Quite simple — the
machine language program currently being executed is inter-
rupted. This interruption is hardware-generated and can
occur at any place within the program. What can interrupt a
machine language program? To find this out we must give some
consideration to the hardware construction of the processor.
The 6502 or 6510 microprocessor is housed within a 40-
pin package, two pins of which have the designations
IRQ and NMI
These are abbreviations for Interrupt ReQuest and Non-Mask-
able Interrupt. If a signal from the outside is sent to one
of these pins, the following events occur:
1. Signal on NMI pin
The processor finishes executing the current instruc-
tion and then attends to the interrupt:
69
Advanced Machine Xanguage
1) The current value of the program counter is placed
on the stack (first high byte then low byte).
2) The processor status register (the flags) is then
pushed onto the stack.
3) The processor reads the contents of the addresses
$FFFA and $FFFB and, interpreting then as the new
value of the program counter, executes an indirect
jump: JMP ($FFFA). The program at this address will
then be executed.
This program "services" the interrupt request.
2. Signal on IRQ pin
Here something similar happens. The current instruction
is completed when the interrupt is registered. With IRQ,
however, the processor first checks the state of the. inter-
rupt flag (bit 3 in the status register). Two cases are
possible:
a) If this flag is set, the interrupt request is ignor-
ed and the program continues running.
b) If the flag was not set, the same procedure is
executed as for NMI:
1) The contents of the program counter and the
flags are saved on the stack.
2) The I flag is set so that any Interrupt re-
quests occurring during the interrupt service
routine will be ignored.
3) The processor gets the new value of the program
counter from addresses $FFFE and $FFFF. The
value- to which these addresses point is used as
the new value of the program counter.
70
Advanced Machine Language
How can we return to the interrupted program? There is
a special machine language instruction for this purpose.
HTI - ReTurn from Interrupt
This instruction reverses the interrupt procedure. The value
of the status register is fetched from the stack, the con-
tents of the program counter is pulled from the stack and
the program continues execution at this address. The inter-
rupted program does not "notice" any of these activities.
The processor saves only the status register — the other
registers, if they are used by the interrupt routine, must
be saved by the interrupt service routine before they are
used and then restored before the return with RTI. For
example
INTERRUPT PHA ; save accumulator
TXA
PHA
save X register
TYA
PHA
save Y register
interrupt service routine
PIA
TAY
restore Y register
PLA
PLA
TAX
restore X register
restore accumulator
HTI
return to interrupted program
71
Advanced Machine Language
The structure of an interrupt service routine is simi-
lar to that of a normal subroutine. The principle difference
is that a subroutine is always called by the nain progran
from specific place, whereas the interrupt routine is called
from the outside by hardware and can be called at any time,
from anywhere. In contrast to a subroutine call, the current
contents of the processor status register are saved in
addition to the return address. If this were not done, the
interrupted program could not continue to function normally
when control was returned to it. Now to the most important
question:
How can an interrupt be generated?
There are several ways that this can happen in the
Commodore 64. We will take a look at the ways in which an
IRQ can be generated. The
video controller VIC 6569 '
and the I/O interface
CIA 6526
can both generate IRQs. The CIA here is the CIA at address
$DCOO.
A non-maskable interrupt (NMI) can be generated by
CIA 6526 (address $DDOO)
72
Advanced Machine Language
as well as
the RESTORE key
In order to successfully prograa our own interrupt
routines, a detailed knowledge of the capabilities and fea-
tures of the peripheral interfaces is indispensable. We will
discuss these interfaces in sufficient detail for our prog-
raming. More information can be obtained from the book The
Anatomy of the Commodore 64 .
73
Advanced Machine Language
2.2 The CIA 6526 > ;
The CIA (Complex Interface Adapter) 6526 is an inter-
face module of the 66XX family which offers two 8-bit input
/output ports, a serial 8-bit shift register, two cascadable
16-bit timers, a real time clock and several control lines.
The CIA has 16 registers which are addressed as succes-
sive memory locations by the microprocessor. The Commodore
64 has two of these chips; the first is located at addresses
$DCOO to $DCOF, the second at $DDOO to $DDOF.
On the next few pages you will find a short description
of these 16 control registers which we will get into in
greater detail in the programs.
74
Advanced Machine Language
Register Port A data register
Access: READ/WRITE
The contents of this register reflect the condi-
tion of the input/output port A.
Register 1 Port B data register
Access: READ /WRITE
The contents of this register
tlon of the Input/output port
reflect the condl-
B.
Register 2 Data direction register A
Access: READ/WRITE
The elghtllnes of data port A can be switched
to Input or output with this register. The cor-
responding bit of the data direction register
Bust be for Input or 1 for output.
Register 3 Data direction register B
Access: READ/WRITE
This register has the same function as register
2, except for port B.
Register 4 Tlner A LSB
Access: READ
When reading this register it returns the cur-
rent condition of timer A (LSB).
Access: WRITE
By means of a write command to this register one
can load the least-significant byte of the value
from which the timer is to count down to zero.
75
1
Advanced Machine Language
Register 5 Timer A MSB
Access :
READ
When reading, the contents of this register give
the current condition of timer A (MSB).
Access: WRITE
One can load the high byte of the value fro*
which timer A is to count down by writing to
this register.
Register 6 Timer B LSB
This register corresponds in function to regis-
ter 4, but applies to timer B.
Register 7 Timer B MSB
This register corresponds in function to regis-
ter 5, except that it applies to timer B.
Register 8 Time of day (real-time clock) tenths of a second
When reading this register, bits 0-3 return the
current state of the real-time clock, specifica-
lly, the tenths of a second in BCD format. Bits
4-7 are always zero.
By writing to register 8 you can, depending on
the preselection of control register B (register
15), either set the tenths of a second on the
real-tine clock or select the alarm time. The
tenths of a second must be given in BCD format,
in which bits 4-7 must be zero.
Access :
READ
Access :
WRITE
76
Advanced Naphlne Language
Register 9 Tine of day, seconds
Access: READ
By reading this register you get the seconds of
the current clock time in BCD format. Bits 0-3
represent the one's place and bits 4-7 the ten's
place.
Access: WRITE
You can either set the clock time or select the
alarm time through a write access to this regis-
ter, similar to register 8. The seconds count
must be in BCD format.
Register 10 Time of day, minutes
Register 10 is organized similarly to register
9, but pertains to minutes.
Register 11 Time of day, hours
Access: READ
Reading this register returns the current hour
value of the real-time clock. Bits 0-3 repre-
sents the one's place. Because the clock counts
only from one to twelve, only one bit is neces-
sary for the ten's place, namely bit 4. Bit 7
corresponds to the American time representation
as a flag for before noon (AM, bit 7=0) or after
noon (PM, bit 7=1).
Access: WRITE
The write access occurs in the same way as for
the other real-time clock registers, although
the significance of the individual bits is the
same as for the read access.
77
Advanced Machine Language
Register 12 Serial shift register
Data is written to this register which will be
shifted bit-by-bit out the serial port. By read-
ing, the data shifted in can be read.
Register 13 Interrupt control register
Access: READ (interrupt data)
Bit tiner A tine-out
Bit 1 timer B time-out
Bit 2 clock tine = alara time
Bit 3 shift register full (for input)
or empty (for output)
Bit 4 signal on FIAG pin
Bit 5-6 always zero
Bit 7 Bit seven is set if at least one of
the bits 0-4 is set in both the inte-
rrupt control registers.
MOTE: READING THIS RBGISTBH 8BASBS IT!
Access: WRITE (interrupt mask)
The significance of bits 0-4 is the same as
above. If bit seven is set in addition, one can
enable the interrupt for the selected function.
If bit 7 is cleared, a one bit disables the
corresponding interrupt possibility.
Register 14 Control register A
Access: READ/WRITE
Bit 0= timer A stop, 1= timer A start
1 1= timer A time-out is signaled on
PB6
Bit 2 0= every timer A time-out creates a
high signal on PB6, 1= every time-out
on tiner A inverts the state of PBS.
78
Advanced Machine Language
Bit 3
Bit 4
Bit 5
Bit 6
Bit 7
Register 16 Control
Access:
Bits
Bits 5
Bit 7
1= timer A counts once from initial
value to zero and stops (one shot),
0= timer A starts automatically after
every time-out (continuous mode).
1= absolute loading of a new value on
timer A.
0= timer counts system clock pulses,
1= timer counts pulses on CNT.
0= serial port is input, 1= serial
port is output.
0= real time clock runs at 60 Hz, 1=
real-time clock runs at 50 Hz.
register B
READ/WRITE
4 same meaning as the corresponding
bits in control register A, but for
timer B and PB7.
6 These bits determine the trigger
source of timer B. 00= timer B counts
system clock pulses, 01= timer B
counts CNT pulses, 10= timer B counts
time-outs on timer A, 11= timer B
counts time-outs on timer A when
CNT=1.
0= set clock time, 1= set alarm tine.
79
Advanced Machine language
2.3 Osing system interrupt
The simplest option for programming your own interrupt
service routine is to add it to the system interrupt. What
generates the system interrupt and what tasks does it per-
form?
The system interrupt is controlled by a timer in CIA 1.
A timer is simply a counter which is decremented by one each
system clock cycle. When the timer counts down to zero (also
known as "timing-out"). it sends a signal to the IRQ input
on the processor. The program will be interrupted and con-
trol passed to an interrupt routine found at $EA31. The
timer consists of two 8-blt registers and can therefore
count up to approximately 2-^16 microseconds or 65 millisec-
onds. The system interrupt is generated every sixtieth of a
second, that is, approximately every 16 ms.
What tasks does this routine perform? The first task is
to check to see if the STOP key is pressed. If this is the
case, a flag in the zero-page is set. This flag is checked
before the execution of every BASIC program. If it is set,
the BASIC program is stopped. The routine for checking the
STOP key increments the internal clock TI which returns the
time in sixtieths of a second.
The second task concerns the cursor. If the computer is
in the direct mode or is awaiting input, it flashes the
cursor. Every twentieth time the interrupt routine is cal-
led, the character over which the cursor is positioned is
reversed. Thus the cursor blinks 20/60=3 times per second.
Another task is the supervision of the datasette. If
the datasette is not under program control (LOAD or SAVE,
for example), the motor is switched on or off depending on
whether a key on the datasette is pressed or not.
80
Advanced Machine Language
The last and perhaps most iaportant task of the inter-
rupt routine consists of reading the keyboard. If a key is
pressed, the key code is determined and the value placed in
the keyboard buffer. The keyboard buffer is ten characters
long. It is thereby possible to press several keys "outside"
of an input routine which then appear on the screen when the
program expects the characters. The number of characters in
the keyboard buffer is also saved. When these tasks are
finished, control exits the interrupt routine and returns to
the interrupted program.
As we mentioned already, the processor gets the address
of the interrupt routine from the memory locations $FFFE and
$FFFF, which are in ROM. How can we change these values?
tefs take a look at exactly what happens when an interrupt
occurs. The address to which the interrupt vector points is
$FF48.
****************************** IHQ jump point
FF48
48
PHA
FF49
8A
TXA
FF4A
48
PHA
save registers
FF4B
98
TYA
FF4C
48
PHA
FF4D
BA
TSX
FF4E
BD
04
01
IDA
$0104, X
get break flag from stack
FF51
29
10
AND
#$10
and test
FF53
FO
03
BEQ
$FF58
not set?
FF55
6C
16
03
JMP
($0316)
BREAK routine
FF58
6C
14
03
JMP
($0314)
interrupt routine
81
Advanced NachiD« Language
First the contents of the registers are saved on the
stack. Then the contents of the status register, which are
autonatically saved on the stack by the processor during an
interrupt, are read and bit 4 is isolated. This is the BREAK
flag which is set by a BRK coninand. The BRK command simu-
lates an interrupt call in software. In order to distinguish
it from a hardware interrupt, the BREAK flag in the status
register is set. The appropriate indirect Jump is made based
on this. If the flag was set, a jump will be made over the
vector at $0316/$0317, else via the vector at $0314/$0315.
The vector $0314/$0315 is the actual interrupt vector
and normally points to the previously mentioned address
$EA31.
If we want to execute additional tasks inside the
interrupt routine, we can proceed in the following manner:
We change the interrupt vector so that it points to our
own routine. When our routine is finished, we Jump to the
normal system interrupt routine so that these tasks can be
performed. Using this procedure we can execute a second
"job" sixty times per second, independent of the main prog-
ram. This routine must naturally not last longer than one
sixtieth of second, otherwise there will be no time for the
main program. A long interrupt routine is characterized by a
slowing down of the main program.
What could the computer execute 60 times per second?
Here your imagination is the only limiting factor. You
could. for example, flash the screen or text on the screen,
similar to the way the cursor is flashed. So that the blink-
ing does not go too fast, a counter must be used so that
82
Advanced Machine Language
the event occura only once every given number of interrupt
calls .
100:
110:
120:
130:
140:
ISO:
160:
170:
180:
190:
200:
210:
220:
230:
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
360:
370:
380:
COOO
COOO
D020
D021
EA31
0314
OOIE
COOO 78
cool A9 OD
C003 AO CO
C005 8D 14
COOS 8C 15
COOB 58
COOC 60
coop CE 26
COlO DO 11
C012 A9 IE
C014 8D 26
C017 AE 21
COIA AD 20
COID 8D 21
.OPT PI
FLASH BACKGHOUND/BORDEH
BORDER
BACK
IRQHOUT =
IRQVEC
NUMBER
I
INIT
$C000
$D020
$0021
$BA31
$314
30
; BORDER
; BACKGROUND
EVERT HALF SECOND
DISABLE INTERPETS
SEI
LDA *<BLINK
LDY *>BLINK
03 STA IRQVEC ; IRQ-VECTOR TO
SCREEN
03 STY IRQVEC+1
CLI
RTS
I
CO BLINK DEC COUNT ; DECREMENT COUNTER
BNE DONE
LDA #NUMBER
CO STA COUNT ; RESET COUNTER
; EXCHANGE COLORS
DO LDX BACK
DO LDA BORDER
DO STA BACK
83
Advanced Machine language
390: C020 8E 20 DO STX BORDER
400: ;
410: C023 4C 31 EA DONE JMP IRQROUT
420: ;
430: C026 IE COUNT .BYT NUMBER ; COUNTER
]C000-C027
NO ERRORS
Let's take a closer look at the above program. The
routine INIT takes care of the initialization and sets the
interrupt vector to the blink routine. Note that interrupts
otherwise possible while the vector is being changed are
blocked by the SBI instruction. If such an interrupt were to
be generated when the low byte pointed to the new value
while the high byte still pointed to the old routine, the
processor would branch to an undefined place in aefflory and
would in all likelihood "crash." If the I bit is set, inter-
rupts can be enabled with CLI and we return with RTS. Now
the new interrupt routine is active.
The following happens at the next interrupt call:
First, the meniory location COUNT is decremented by one. If
this does not yield a value of zero, execution branches to
the label DONE and the normal interrupt routine is executed
from there. If, however, the counter was zero, it is first
reset to value 30 and the background and border colors are
exchanged, creating the flash effect.
We can activate our routine by calling it with SYS
12*4096. Immediately the screen begins to flash twice a
second. This interrupt routine runs completely independently
of a BASIC or machine language program until the interrupt
vector is set back to the old routine. This is done by
84
Advanced Machine Language
pressing the RUN/STOP-HESTOHE keys, for example.
He can easily change the flash frequency with the label
NUMBER; it gives the number of sixtieths of a second between
color changes.
As a second example of interrupt routines, we want to
change the cursor attributes. The cursor should not blink,
but only be represented as an inverted character. We cannot
simply place our new routine ahead of the normal interrupt
routine. We must replace the part which pertains to the
cursor blinking.
*****************************
EA31
20
EA
FF
JSR
$FFEA
EA34
AS
CC
LDA
$CC
BA36
DO
29
BNE
$EA61
EA38
C6
CD
DEC
$CD
BA3A
DO
25
BNE
$EA61
BA3C
A9
14
LDA
#$14
EA3B
85
CD
STA
$CD
EA40
A4
D3
LDY
$D3
BA42
46
CF
LSR
$CF
EA44
AE
87
02
LDX
$0287
EA47
Bl
Dl
LDA
($D1),Y
EA49
BO
11
BCS
$EA5C
EA4B
E6
CF
INC
$CF
EA4D
85
CE
STA
$CB
EA4F
20
24
EA
JSR
$EA24
EA52
Bl
F3
LDA
($F3),Y
EA54
8D
87
02
STA
$0287
EA57
AE
86
02
LDX
$0286
EA5A
A4
CB
LDA
$CE
Interrupt routine
stop key, increment time
blink flag for cursor
not blinking, then continue
decrement blink counter
not zero, then continue
set blink counter back to 20
and save
cursor column
blink switch zero then C=l
color under cursor
set character code
blink switch on, continue
blink switch on
save character under cursor
calculate pntr in color RAM
get color code
and save
color code under cursor
character under cursor
85
Advanced Machine Language
EA5C 49 80 BOR *$80 Invert RVS bit
BASE 20 IC BA JSR $EA1C set cursor char and color
The cursor blinking is realized as follows. First a
check is made to see if the cursor is active. If not, the
following part is skipped. Otherwise the blink counter is
decremented. If it is not zero, the remaining portion will
skipped. Otherwise, the phase of the cursor is checked to
see if it is in the inverted phase. The current or stored
character is inverted and displayed depending on this. The
same happens in the color RAM with the character color and
the current cursor color.
We want to modify the routine so that we have a steady
cursor. We can do this with the following program.
100:
110:
120:
130:
140:
150:
160:
170:
180:
190:
200:
COOO
FFEA
OOCC
OOCF
0287
OOCE
OODl
OOFS
.OPT PI
MODIFY CURSOR
STOP = $FFEA ;READ STOP KET
CURSFLAG = $CC J FLAG FOR VISIBLE
CURSOR
REVERSE = $CF ; FLAG FOR INVERTED
CHARACTER
CURSCOL = $287 ; COLOR UNDER
CURSOR
CURSCHAR = $CE ; CHARACTER UNDER
CURSOR
CHAR = $D1 ; POINTER IN VIDEO
RAM
COLOR = $F3 ; POINTER IN COLOR
RAN
86
Advanced Machine Language
210:
220:
230:
240:
250:
260:
270:
280:
290:
300:
31j0:
320:
330:
340:
350:
380:
370:
380:
390:
400:
410:
420:
430:
440:
450:
BA24
00D3
0286
0314
EA61
COOO 78
SBTCOL
COLUMN
COLSTR
IRQVEC
CONTIRQ
I
INIT
COOl A9 OD
C003 AO CO
COOS 8D 14 03
C008 8C IS 03
COOB 58
COOC 60
GOOD 20 EA FF NEHCURS
COlO AS CC
C012 DO ID
C014 A4 03
C016 AS CF
C018 DO 17
COIA E6 CF
COIC 20 24 EA
COIF Bl 01
, C021 86 CE
C023 49 80
= $EA24 ;SET POINTER TO
COLOR RAM
$03 ; CURSOR COLUMN
$286 ; CURSOR COLOR
$314 ;IRQ VECTOR
= $EA61 {CONTINUE IRQ
SEI ; DISABLE INTER-
RUPTS
LDA *<NEWCURS
LDY *>NEHCURS
STA IRQVEC ; IRQ VECTOR TO
NEW ROUTINE
STY IRQVEC+1
CLI
RTS
JSH STOP ; TEST STOP KEY
LDA CURSFLAG ; CURSOR
VISIBLE?
BNB NOCURSOR ; NO
LDY COLUMN ; CURSOR COLUMN
LDA REVERSE ; CHARACTER AL-
READY REVERSED?
BNE NOCURSOR ; YES
INC REVERSE ; SET FLAG FOR
REVERSE
JSR SETCOL ; POINTER IN COLOR
RAM
LDA (CHAR),Y ; POINTER AT
CURSOR POSITION
STA CURSCHAR ; SAVE
EOR #$80 ;FLIP RVS BIT
87
Advanced Machine Language
460: C025 91 Dl STA (CHAR),Y ; AND IN VIDEO
RAM
470
C027
Bl
F3
LDA
(COLOR), Y .COLOR
480
C029
8D
87
02
STA
CORSCOL ; SAVE
490
C02C
AD
88
02
LDA
COLSTR ; CURSOR COLOR
500
C02F
91
F3
STA
(COLOR), Y ;SET
510
C031
4C
61
EA
NOCURSOR JMP
CONTIRQ ; CONTINUE IRQ
1C000-C034
NO ERRORS
When you activate this routine with SYS 12*4096, the
cursor is simply replaced with an inverted character. You
can modify this routine according to your own taste; the
cursor color need not be the same as the character color,
for instance — it could always be one color. Instead of the
inverted representation you can do something different, such
as display a line. It would also be possible to leave the
character unchanged and simply alternate between two colors.
You should consider these examples only as suggestions for
your own experiments with the interrupt routine — the poss-
ibilities are numerous.
Here we can briefly discuss a method of inhibiting the
STOP key. Because the test for the STOP key is the first
thing done in the interrupt routine, we can bypass this test
by changing the interrupt vector to point beyond it. A
running BASIC program can no longer be stopped with the STOP
key:
POKE 788, PEEK(788)+3
The vector is simple incremented by three bytes so that the
test is bypassed. A disadvantage of this method is that the
88
Advanced Machine language
Internal clock TI and TI$ no longer run. This is because the
routine that tests the STOP key also keeps the clock up-
dated.
An additional application of the system routine is the
execution of a certain action upon a keypress. It is possib-
le, for example to call a hardcopy routine which outputs
the screen contents to a printer by pressing a function key.
The interrupt routine can check to see if the key was
pressed. If this is the case, a routine can be called which
performs the special task. Here too, many applications are
possible, such as switching between two screen pages. Here
is an example of this:
100:
110:
12Q:
130:
140:
150:
160:
170:
180:
190:
200:
210:
220:
230:
240:
250:
033C
0003
0005
DDOO
0288
0314
EA31
DOOO
D800
COOO
0001
028D
00C5
.OPT PI
SWITCH SCREEN PAGES
PNTl
PNT2
VIDBOMAP
VIDEOPGE
IRQVEC
IRQOLD
CHARGEN
COLOR
C0L0R2
PORT
CTRL
KEY
3
5
$0000
648
$314
$EA31
$0000
$0800
$C000
1
853
$C5
; 16K VIOEO RANGE
; CHARACTER GEN-
ERATOR
; COLOR RAM
; STORAGE FOR COLOR
RAM
PROCESSOR PORT
FLAG FOR CONTROL
LAST KEY
89
Advanced Machine Language
260: 0004 Fl
270: ;
280: 033C
290: ;
300: 033C 78 INIT
310: 033D 20 94 03
320: 0340 Ag 4C
330: 0342 AO 03
340: 0344 8D 14 03
350: 0347 8C 15 03
360: 034A 58
370: 034B 60
380: ;
390: 034C AD 8D 02 TEST
400: 034F 29 04
410: 0351 FO 09
420: 0353 A5 C5
430: 0355 C9 04
440: 0357 DO 03
450: 0359 20 5F 03
460: 035C 4C 31 EA NOSWITCH
470: ;
480: 035F AO 00 SWITCH
490: 0361 84 03
500: 0363 84 05
510: 0365 A9 D8
520: 0367 85 04
530: 0369 A9 CO
4 ; MATRIX NUMBER OF
Fl KEY
*= 828
SEI
JSR SETCHAR ;COPY CHARACTER
GENERATOR
LDA #<TEST
LDY #>TEST
STA IRQVEC ; POINTER TO NEW
ROUTINE
STY IRQVEC+1
CLI
RTS
LDA CTRL ; CONTROL KEY
PRESSED?
AND *%100
BEQ NOSWITCH ; NO
LDA KEY ;F1 PRESSED
CMP #F1
BNE NOSWITCH ; NO
JSR SWITCH ; EXCHANGE PAGES
JMP IRQOLD
LDY #0
STY PNTl
STY PNT2
LDA #>COLOR ; POINTER TO COLOR
RAM
STA PNTl+1
LDA #>C0L0H2 ; POINTER TO
90
Advanced Machine Language
RAO •
036B
85
06
STA
550:
036D
A2
04
LDX
560:
036F
Bl
03
SWAP
LDA
570:
0371
48
PHA
580:
0372
Bl
05
LDA
590:
0374
91
03
STA
600:
0376
68
PLA
610:
0377
91
05
STA
620:
0379
C8
INY
630:
037A
DO
F3
BNE
640:
037C
E6
04
INC
650:
037E
E6
06
INC
660:
0380
CA
DEX
670:
0381
DO
EC
BNE
680:
0383
AD
00
DD
LDA
690:
0386
49
03
EOR
700:
0388
8D
00
DD
STA
710:
038B
AD
88
02
LDA
720:
038B
49
CO
EOR
730:
0390
8D
88
02
STA
740:
0393
60
RTS
750:
1
760:
0394
AO
00
SETCHAR
LDY
770:
0396
84
03
STY
780:
0398
Ag
DO
LDA
782:
039A
85
04
STA
784:
039C
A2
10
LDX
786:
039E
A9
33
LOOP
LDA
790:
03A0
85
01
STA
STORAGE FOR COLOR
PNT2+1
#4 ; NUMBER OF PAGES
(PNTl) ,Y
(PNT2),Y
(PNTD.Y ;SWAP COLOR
STORAGE
(PNT2),Y
SWAP
PNTl+1
PNT2+1
;NEXT PAGE
SWAP
VIDEOMAP
*%11 ; ACCESS ADDRESS
FOR VIC
VIDEOMAP
VIDEOPGE
*$C0 ; SCREEN PAGE
VIDEOPGE
#0
PNTl
#>CHARGEN
PNTl+1
#$10
*$33
PORT ;TURN ON CHARACTER
GENERATOR
91
Advanced Machine Languafe
800:
03A2
Bl
03
LDA
(PNTl) ,Y
810:
03A4
48
PHA
820:
03A5
A9
30
LDA
#$30
830:
03A7
85
01
STA
PORT
TURN ON RAM
840:
03A9
68
PLA
850:
03AA
91
03
STA
(PNTl) ,Y
860:
03AC
C8
I NY
870:
03AD
DO
EF
BNE
LOOP
880:
03AF
E6
04
INC
PNTl+l 1
NEXT PAGE
890:
03B1
CA
OEX
900:
03B2
00
EA
BNE
LOOP
910:
03B4
A9
37
LDA
#$37 ;
STANDARD CONFIG
URATION
920:
03B6
85
01
STA
PORT
930:
03B8
60
RTS
1033C-03B9
NO ERRORS
This program allows us to switch between two screen
pages. The first page lies as usual at $0400, while we have
placed the second page at address $C400. It is also possible
for the second page to have its own sprites. The sprite
pointers must be at address $C7F8. The base address of this
screen is therefore located at $C000. For example, the
address space from $C800 to $CFFF is available for storing
sprites and offers room for 32 different sprite patterns
(sprite numbers 32 to 63). Because the video controller
always expects the color RAM to be at address $D800, we can
store the color of the currently invisible page at $C000 to
$C3FF. Furthermore, we must take into consideration the fact
that the VIC in the upper 16K from $C0OO to $FFFF cannot
access the character generator ROM. We therefore copy the
character generator from ROM to the RAM at the same address-
92
Advanced Machine Language
es.
The actual interrupt routine checks bit 2 in the flag
for the control key. If this bit is set, the control key was
pressed. If the Fl key was also pressed, the routine which
exchanges the color storage and sets the parameters for
displaying the other screen page is called. Finally, a
branch is made to the normal interrupt routine.
When we assemble our program and activate it with SYS
828, we can switch to the second screen page simply by
pressing the CTRL and Fl keys at the same time. The first
time you make the switch, you should clear the screen be-
cause random values will be left in the video RAN. Pressing
the two keys again returns you to the original screen. The
cursor will remain at the same place.
As an additional suggestion, you could try to display
the clock time during the interrupt routine. The time will
then appear on the screen at all times, Independent of other
program activities. You can find such a routine in the book
Tricks and Tips for the Commodore 64 .
Another equally interesting possibility for an inter-
rupt routine involves sprites. One or more sprites can be
moved during each interrupt. Programming the sound chip can
also be done in an interrupt routine. Here sound sequences
or entire pieces of music can be played completely independ-
ently of other programs. You can see that the possibilities
which are offered to you are virtually unlimited. Before we
begin to generate our own interrupts, we will present two
more routines which are tied to the system interrupt.
93
Advanced Machine Language
You nay find the following program quite useful if you
use the user port to interface with devices of your own. The
program is tied into the system interrupt and gives you a
continual display of the individual bits of the user port.
The direction register is displayed in the first screen
line. This allows you to see which lines are set for input
(=0) or output (=1). In the next line the states of the user
port lines are displayed; a indicates a low signal, a high
signal is displayed as a 1. Both displays are also given in
hexadecimal form.
100:
033C
.OPT
PI
110:
120:
;USBR PORT DISPLAY
130:
140:
DDOO
CIA2
$DD00
150:
DDOl
USERPORT
CIA2+1
160:
DD03
DIRECTION=
CIA2+3
170:
t
180:
0288
VIDE0P6E
648
190:
D800
COLORRAM
$D800
200:
210:
0007
COLOR
7 ; YELLOW
220:
)
230:
0314
IRQVEC
$314
240:
EA31
IRQOLD
$EA31
250:
OOFB
PNT
$FB
260:
1
270:
033C
*=
828
280:
033C
78
INIT
SEX
290:
033D
AD
14
03
LDA
IRQVEC
300:
0340
49
7E
EOR
#< IRQOLD DISP
310:
0342
8D
14
03
STA
IRQVEC
94
Advanced Machine Language
320:
0345
AD
15
03
LDA
IHQVEC+1
330:
0348
49
B9
EOR
*> IRQOLS
DISP
340:
034A
8D
15
03
STA
IRQVEC-t-1
350:
034D
58
CLI
360:
034E
60
RTS
370:
»
380:
034F
A5
FB
DISP
LDA
PNT
390:
0351
48
PHA
s
SAVE POINTER
400:
0352
AS
FC
LDA
PNT+1
410:
0354
48
PHA
420:
0355
A9
IC
LDA
#28
430:
0357
85
FB
STA
PNT ;
POINTER TO VIDEO
RAM
440:
0359
AD
88
02
LDA
VIDEOPGE
450:
035C
85
FC
STA
PNT+1
•
460:
035E
AD
03
DD
LDA
DIRECTION
470:
0361
AO
00
LDY
#0 ;
DIRECTION IN TOP
LINE
480:
0363
20
77
03
JSR
DISPLAY
; DISPLAY
490:
0366
AD
01
DD
LDA
USERPORT
500:
0369
AO
28
LDY
#40 ;
USER PORT IN
SECOND LINE
510:
036B
20
77
03
JSR
DISPLAY
{DISPLAY
520:
036E
68
PLA
530:
036F
85
FC
STA
PNT+1 J
GET POINTER BACK
540:
0371
68
PLA
550:
0372
85
FB
STA
PNT
560:
0374
4C
31
EA
JNP
IRQOLD ;
TO NORMAL IRQ
570:
i
580:
0377
48
DISPLAY
PHA
1
SAVE VALUE FOR
HEX DISPLAY
590:
0378
A2
08
LDX
#8
600:
037A
OA
LOOP
ASL
5
HIGHEST BIT IN
95
Advanced Machine Language
CARRY
610:
037B
48
PHA
620:
037C
A9
30
IDA
#"0"
; DISPLAY ZERO
630:
037E
90
02
BCC
NULL
640:
0380
A9
31
LDA
*"1"
; DIPLAY ONE WHEN
C = l
650:
0382
91
FB
NULL STA
(PNT) ,Y
660:
0384
A9
07
LDA
♦COLOR
;AND SET COLOR
670:
0386
99
IC
D8
STA
C0L0RRAM+28,Y
680:
0389
C8
I NY
690:
038A
68
PLA
700:
038B
CA
DEX
710:
038C
DO
EC
BNB
720:
730: '
;HEX DIPLAY
740:
750:
038E
C8
INY
760:
038F
68
PLA
770:
0390
48
PHA
780:
0391
4A
LSR
790:
0392
4A
LSR
SHIFT UPPER
NYBBLE DOWN
800:
0393
4A
LSR
810:
0394
4A
LSR
820:
0395
20
99
03
JSR
ASCII
HIGH NYBBLE
830:
0398
68
PLA
840:
0399
29
OF
ASCII AND
*«1111
850:
039B
C9
OA
CMP
#10
860:
039D
90
02
BCC
SMALLER
870:
039F
69
06
ADC
#6
880:
03A1
69
30
SMALLER ADC
#"0"
CONVERT TO ASCI
890:
03A3
29
3F
AND
*!lillllll
; CONVERT TO
SCREEN CODE
96
Advanced Machine Language
900: 03A5 91 FB
910: 03A7 Ag 07
920: 03A9 99 IC D8
930: 03AC C8
940: 03AD 60
]033C-03AE
NO ERRORS
We have done the initialization somewhat differently.
He eXclu8ive-0R the old value of the IRQ vector with the new
value and thereby arrive at a switch between the old value
$EA31 and our new routine DISPLAY with every call of SYS
828. Thus if you want to turn the display off, simply enter
SYS 828 again and the interrupt vector will be set back to
$EA31.
The program itself consists of a main program which at
the start saves the necessary memory locations on the stack
so that other programs which might use these addresses are
not disturbed. Then the pointer PNT is set to the 28th
column of the first screen line, the value of the data
direction register loaded, and the subroutine for display
called. After this, Y is set to 40 so that the display
routine writes one line lower, and the contents of the user
port are passed. Now the pointers are restored and the
branch is made to the normal IRQ routine.
The display routine prints the value in the accumulator
first in binary and then in hexadecimal. We use a loop for
the 8 bit positions in the binary representation. During
each pass through the loop, the uppermost bit is shifted
into the carry with ASL. If this bit was a "1," then the
carry is set and we output a "1" on the screen, otherwise a
STA (PNT),Y
LDA #COLOR ;AND SET COLOR
STA C0L0RRAN4-28, Y
INY
RTS
97
Advanced Machine Language
"0". After the binary display, the values temporarily stored
on the stack are displayed in hexadecinal. The upper nybble
(four bits) is right-shifted into the lower nybble, then
converted to ASCII and displayed on the screen. The saae is
then done for the lower nybble.
When you activate the routine with SYS 828, the follow-
ing representation appears on the screen, for exaaple:
00000000 00
FFFFFFFF FF
This is the value after the computer is turned on. The
user port is set to input and the open inputs yield a high
signal. Switch the user port to output and write 100 to it.
POKE 56579, 255
POKE 56577, 100
You get the following display:
FFFFFFFF FF
01100100 64
The bits 2, 5, and 6 are set; this corresponds to the hex
number $64 or decimal 100.
The next routine is similar to the previous. It pro-
vides us with a continual display of the remaining free
memory space. Ne accomplish this like the FRE function each
Interrupt. We simply calculate the difference between the
end of the array table and the start of the strings. In
contrast to the real FRE function, no garbage collection is
98
Advanced Machine Language
perforaed in the interrupt routine. If we want to display
the free space in decimal, it requires a conversion to
floating-point format and again to ASCII representation.
This takes time, although we could put up with that. The
main disadvantage of such a method is that we must save all
used memory locations on the stack because the interrupt can
stop the program at any place. We would have to save 20 or
more memory places, which, for one, requires time, and for
another, requires quite a bit of space on the stack. He will
therefore display the free memory space in hexadecimal for-
mat. This is equally informative and significantly faster.
100:
033C
.OPT
PI
110:
;
120:
; DISPLAY
FREE
MEMORY SPACE
130:
.
140:
0031
ARRAYEND
$31
150:
0033
STRGSTRT
$33
160:
i
170:
0400
VIDEO
1024
180:
D800
COLOR
$D800
190:
\
200:
0007
CLRCODE
7 ; YELLOW
210:
1
220:
0314
IRQVEC
$314
230:
EA31
IRQOLD
$EA31
240:
» -
250:
COOO
INIT
* =
828
260:
033C
78
SEI
270:
033D
A9
49
LDA
*<FRBE
280:
033F
AO
03
LDY
#>FREE
290:
0341
8D
14
03
STA
IRQVEC
300:
0344
8C
15
03
STY
IRQVBC+1
99
Advanced Machine Language
310:
0347
58
CLI
320:
0348
60
RTS
330:
*
340:
0349
38
FREE
SEC
350:
034A
A5
33
LDA
STRGSTRT
360:
034C
E5
31
SBC
ARRAYBND
370:
034E
08
PHP
380:
034F
AO
25
LDY
#37
390:
0351
20
61
03
JSR
DISPLAY
400:
0354
28
PLP
410:
0355
A5
34
LDA
STRGSTRT+l
420:
0357
E5
32
SBC
ARRAYEND+1
430:
0359
AO
23
LDY
#35
440:
035B
20
61
03
JSR
DISPLAY
450:
035E
4C
31
EA
JMP
IRQOLD
460:
0361
48
DISPLAY
PHA
470:
0362
4A
LSR
480:
0363
4A
LSR
490:
0364
4A
LSR
500:
0365
4A
LSR
510:
0366
20
6A
03
JSR
ASCII
520:
0369
68
PLA
530:
036A
29
OF
ASCII
AND
#!K1111
540:
036C
C9
OA
CMP
#10
550:
036E
90
02
BCC
SMALLER
560:
0370
69
06
ADC
#6
570:
0372
69
30
SMALLER
ADC
#"0"
580:
0374
29
3F
AND
#!l!llllll
590:
0376
99
00
04
STA
VIDEO, Y
600:
0379
A9
07
LDA
#CLRCODE
610:
037B
99
00
D8
STA
COLOR, Y
620:
037E
C8
I NY
630:
037F
60
RTS
100
Advanced Machine Langnage
]033C-0380
NO ERRORS
The anount of free space is displayed continually on
the screen after calling the routine with SYS 828. Try the
following BASIC program and watch the display.
100 DIN A$(200)
110 FOR 1= 1 TO 200 : A$(I) = CHR$(1) : NEXT
You can watch the free memory space get smaller and
smaller. Now enter ?FRE(0). During the approximately 4 sec-
onds which this function requires, you can see that the free
memory space changes constantly.
If you work with ASSEMBLER 64, you can see how the
symbol table is created in pass 1 because it uses the same
pointers as BASIC.
101
Advanced Machine Iianguage
2.4 Video controller interrupts
Now that we have learned how to use the timer control-
led system interrupt for our own purposes, we want to be
able to generate interrupts ourselves and execute corres-
ponding routines.
We will take a look at the chips which are capable of
generating interrupt requests. These include the two CIA
6526s, of which CIA 1 can generate an IRQ and CIA 2 an NMI.
The video controller VIC 6567 can also generate an inter-
rupt. The registers necessary for the interrupt will be
described here.
Register 18 Access READ
A read access to this register returns the
number of the raster line currently being disp-
layed on the screen. Because the raster line
number can be larger than 255, bit 7 of regis-
ter 17 is used for the carry.
Access WRITE
When your write to this register, you can set
the raster line at which the VIC will generate
an interrupt request.
Register 25 Interrupt Request Register
This register signals an interrupt request by
the VIC. The individual bits stand for various
interrupt sources.
Bit The video controller reached the ras-
ter line which was set in register 18.
Bit 1 A sprite collided with a background
character. The number of the sprite is
102
Advanced Machine Language
recorded in register 31.
Bit 2 Two sprites collided. The numbers of
the sprites involved are saved in
register 30.
Bit 3 A strobe was generated by the light
pen. The X and Y positions are record-
ed in registers 19 and 20.
Bit 7 This bit is set whenever any of the
others are set.
Register 26 Interrupt Mask Register
The significances of the bits correspond to the
those in register 25. An interrupt request is
generated only if the corresponding bit in the
IMR is set and the interrupts are enabled.
Register 30 Sprite-sprite collision
If two sprites collide, the bits are set ac-
cording to the numbers of the sprites involved.
Bit 2 in register 25 is also set. These bits
must be reset after reading the results.
Register 31 Sprite-background collision
If a sprite encounters a background character,
the number of the sprite is recorded in this
register and bit 1 of register 25 is set at the
same time. This register must also be reset
after use.
The video controller can generate interrupts based on four
different events:
103
Advanced Machine Language
* raster line reached
* sprite-background collision
* sprite-sprite collision
* light pen
The video controller records these conditions in register 25
if one of the four events occurs. The Interrupt Mask Regis-
ter (IMH) decides whether an interrupt request to the proc-
essor will generated. If a bit is set in this register, the
corresponding event will cause an interrupt request to be
generated. This register may be read from and written to
like a RAM memory location. If a bit is to be set or
cleared, that is, an interrupt is to be enabled or disabled,
the appropriate procedure must be followed.
Setting a bit
Set the desired bit and also bit 7. Then write the
resulting value to the interrupt mask register. If, for
example, you want to permit an interrupt by a sprite-sprite
collision (bit 2):
LDA #%10000100
STA IMR
You set the desired bit and bit number 7. The other bits (0,
1, and 3) will not be changed.
Clearing a bit
If you want to disable an interrupt, the corresponding
bit must be cleared. You must set the desired bit, but bit 7
must be cleared. For example, to disable the sprite-sprite
collision:
104
Advanced Machine Language
LDA #ik00000100
STA IMR
Here too the unset bits remain unchanged. It is not possible
to read the interrupt mask register. If a program requires
the value of the interrupt mask, it can be stored in RAM at
the same time it is written to the VIC in order to save the
value.
A second peculiarity must be taken into account for the
Interrupt Request Register (IRR). If the video controller
has generated an interrupt request, this register must be
reset, otherwise another interrupt will be generated immed-
iately following the exit from the interrupt routine. A set
bit can be cleared in the same manner as is done in the
interrupt mask register, simply by writing this bit back
into the interrupt request register. This can be done most
easily by reading the value and immediately writing it back.
For example:
LDA IRR
STA IRR
Now the bit pattern is in the accumulator and the individual
bits can be tested by masking. This is always necessary
whenever several interrupt sources are active, such as the
normal system interrupt through the timer and an additional
interrupt via the video controller. Because both interrupts
must go over the same vector, we must first determine in our
interrupt service routine what source generated the request
and then branch accordingly. An example will make all of
this quite clear if it sounds a bit confusing at the moment.
105
Advanced Machine Language
We want to use the raster interrupt in order to display
16 sprites on the screen at the sane tine. Since the video
controller can only display 8 sprites at a tine, we must
display each set of 8 sprites in succession.
The whole thing functions as follows:
Eight sprites are to be displayed in the upper half of
the screen. If the video controller has displayed the upper
half, we generate an interrupt. In the interrupt routine we
set the parameters for the sprites which are to be displayed
in the lower half of the screen. At the same time, we must
prepare the next raster interrupt for the end of the screen
so that we can again switch back to the upper 8 sprites.
100:
110:
120:
130:
140:
160:
165:
170:
180:
190:
200:
202:
203:
033C
DOOO
DOOl
D012
D019
DOIA
0064
00C8
005A
OOAA
.OPT PI
RASTER INTERRUPT
VIC =
SPHITBY =
RASTER =
IRR =
INR
LINEl =
LINE2 =
YCOOHDl =
YC00HD2 =
$DOO0
VIC + 1
VIC+18
VIC+25
VIC+26
100
200
90
170
; VIDEO C0MTH01.LER
; SPRITE Y-COORD-
INATE
; RASTER ilNE
; INTERRUPT REQUEST
REGISTER
; INTERRUPT MASK
REGISTER
; FIRST LINE
; SECOND LINE
; FIRST Y-COORD-
INATE
; SECOND Y-COORD-
106
Advanced Machine Language
INATE
210:
1
220:
0314
IRQVEC
=
$314
230:
EA31
IRQOLD
=
$EA31
240:
*
300:
033C
* =
828
310;
033C
78
INIT
SEI
320:
033D
A9
64
LDA
#LINB1 ; FIRST INTERRUPT
330:
033F
8D
12
DO
STA
RASTER ;AT LINE 100
340:
0342
AD
11
DO
LDA
RASTER-1
350:
0345
29
7F
AND
*X01111111 ; ERASE HIGH
BIT
380:
0347
8D
11
DO
STA
RASTER-1
370:
034A
A9
81
LDA
#!K10000001 ; INTERRUPT
380:
034C
8D
lA
DO
STA
IMR
; RASTER LINE
390:
034F
A9
5B
LDA
#<TESTIRQ
400:
0351
AO
03
LDY
#>TESTIRQ
410:
0353
8D
14
03
STA
IRQVEO
; VECTOR TO NEW
420:
0356
80
15
03
STY
IRQVEO+1
; ROUTINE
430:
0359
58
OLI
440:
035A
60
RTS
450:
t
460:
035B
AD
19
DO TESTIRQ
LDA
IRR
;READ REGISTER
470:
035E
8D
19
DO
STA
IRR
;AND ERASE
480:
0361
29
01
AND
*%1
;IRQ BY RASTER
LINE
490:
0363
DO
03
BNE
OK
; YES
500:
0365
40
31
EA
JMP
IRQOLD
; NORMAL IRQ
510:
»
520:
0368
AD
12
DO OK
LDA
RASTER
; CURRENT LINE
530:
038B
09
08
ONP
*LINE2
;>= SECOND LINl
540:
036D
BO
16
BOS
SEOOND
; YES
545:
107
Advanced Machine language
550: 036F AO C8
LDY
*LINE2
;NEXT IRQ AT 2ND
LINE
555: 0371 A9 AA
IDA
#YC00RD2 ;NEW SPRITE
COORDINATE
560
: 0373 8C 12
DO
BACK
STY
RASTER
;SET RASTER LINE
570
0376 A2 OE
LDX
#14
590
: 0378 9D 01
DO
LOOPl
STA
SPRITEY,
X ; SPRITE COORD-
INATES
600
: 037B CA
DEX
; CHANGE
610
: 037C CA
DEX
620
: 037D 10 F9
BPL
LOOPl
630
f
640
037F 68
PLA
;GET REGISTERS
BACK
650
0380 A8
TAY
660
0381 68
PLA
670.
0382 AA
TAX
680:
0383 68
PLA
690:
0384 40
HTI
700:
1
710:
0385 AO 64
SECOND
LDY
#LINE1
PARAMETERS FOR
FIRST LINE
720:
0387 A9 5A
LDA
#YC00RD1
730:
0389 4C 73
03
JMP
BACK
J033C-038C
NO ERRORS
In order to test our routine, you can activate 8
sprites with the following program. When you then start the
interrupt routine with SYS 828, 16 sprites suddenly appear
on the screen. Eight are at the y-coordinate 90 and the
other 8 at the y-coordinate 170. Each time the upper 8
sprites are displayed we change the sprite parameters in the
ICS
Advanced Machine Language
interrupt routine so that the video controller can display
the same sprites again in the lower half of the screen.
100 FOR 1=0 TO 7:P0KK 2040+1 , 12: NEXT
110 V=53248
120 POKE V+21,255
130 FOR 1=0 TO 7:POKEV+2*I,(I+1)*30:POKEV+2*I+1,70:NEXT
140 FOR 1=0 TO 7:POKEV+39+I,l:NEXT
In addition to the sprite coordinates, you can change
all of the other sprite parameters as well, such as the
color or size. You can also change the sprite pointers so
that other sprite patterns can be displayed, even multico-
lor.
You can do more than display 16 sprites. If you change
the display mode in the raster interrupt routine, you can
display a split screen. The top half could display high-
resolution graphics while text appears in the lower half. If
you place the line number at which a raster interrupt is to
be generated into a specific memory location, you can even
continually change it from BASIC with a POKE loop so that
the border changes. Superimposed effects can also be ach-
ieved in this manner. As you can see, there are many pos-
sibilities here also.
109
Advanced Machine Language
2.5 CIA 6526 Interrupts
Now that we are acquainted with the interrupts gene-
rated by the video controller, we want to look at the CIA
6526, which has very diverse interrupt sources.
The CIA 6526 is a universal input/output interface chip
with two parallel 8-bit ports, a serial shift register, two
16-bit timers, a real-tine clock as well as several hand-
shake lines.
The two parallel 8-bit ports serve to input and output
data. Of the total of four ports contained in the two CIAs,
three are used by the systeo; the two ports of CIA 1 are
used for reading the keyboard and joysticks. Port A of CIA 2
yields the 16K address selection for the video controller
(bit and 1)1 bit 2 is free, while bits 3 to 7 are used for
the serial bus. Port B of CIA 2 is available to the user
through the user port, provided you have not inserted an RS-
232 cartridge in the user port.
The timers are used as follows by the operating system:
CIA 1 Timer A 60 Hz system interrupt
Timer B serial bus (time-out)
read and write datasette
CIA 2 Timer A send RS 232
Timer B receive RS 232
If you want to use the timers for your own purposes,
you can use the CIA 2. CIA 2 does not generate an IRQ.
however, but an NMI. If you do not want to use the serial
110
Advanced Machine Language
bus at the saae time as your routine, you can use timer B in
CIA 1 and thereby generate an IRQ. In special cases you can
even dispense with the system interrupt and use timer A.
The real-time clocks are not used by th^ operating
system; there are therefore two of them at your disposal.
You can generate either an IRQ (CIA 1) or an NMI (CIA 2)
with the alarm time.
The serial shift registers can also be used freely. The
line FLAG which serves as a handshake input, sets the cor-
responding bit in the interrupt control register of CIA 2 on
a trailing edge.
The input/output and handshake lines are used primarily
for connecting custom peripheral devices. Interrupt program-
ming is often required in such applications. We will later
describe interfacing a printer to the user port as an exam-
ple; the primary aim is to include the routine in the oper-
ating system so that the device can be addressed by the
usual BASIC commands OPEN, PHINT#, etc.
The next example uses the real-time clock to make an
alarm clock. We will use CIA 2 which will generate an NMI
when the alarm time is reached.
100: 033C .OPT PI
110:
120:
130:
140:
ALARM WITH REAL-TIMB CLOCK IN CIA2
DDOO CIA2 = $DD00 ; BASE ADDRESS CIA
150: DD08 TODIO = CIA2+8 ; TENTHS OF A
SECOND
111
Advanced Machine Language
160:
DD09
TODSEC
CIA2-*-9
170:
DDOA
TODMIN
=
CIA2+10
180:
DDOB
TODSTD
CIA2+11
190:
200:
DDOD
ICR
CIA2+13
210:
DDOE
CRA
=
CIA24-14
220:
DDOF
CRB
=
CIA2+15
230:
D020
BORDER
—
$D020
240:
0002
RED
2
250 :
t
260 :
0318
NNI
$318
270:
FE56
COMTNMI
$FE56
280:
t
290:
;TIME 12H 00' 00.0"
300:
0000
TENTHS
310:
0000
SECONDS
$00
320:
0000
MINUTES
$00
330:
0001
HOURS
$01
340:
350:
; ALARM TIME
12H 00' 05
360:
0000
ALARM. 10
370:
0005
ALARM. SC
$05
380:
0000
ALARM. MN
$00
390 :
0001
ALARM. HR
$01
400:
i
410:
033C
* =
828
420:
>
430:
;SET CLOCK TIME
440:
033C AD
OE DD
LDA
CRA
450:
033F 09
00
ORA
#$00 ;
; SECONDS
; MINUTES
; HOURS
; INTERRUPT CON-
TROL REGISTER
; CONTROL REG-
ISTER A
.■CONTROL REG-
ISTER B
; BORDER COLOR
; NMI-VECTOH
;0LD NMI
CLOCK TIME 60 HZ
112
Advanced Machine Language
460: 0341 8D OE DD
470:
480: 0344 AD OF DD
490: 0347 29 7F
500: 0349 8D OF DD
510:
520: 034C AS 01
530: 034E 8D OB DD
540: 0351 A9 00
550: 0353 8D OA DD
580: 0358 A9 00
570: 0358 8D 09 DD
580: 035B A9 00
590: 035D 8D 08 DD
600:
610: 0360 AD OF DD
620: 0363 09 80
630: 0365 8D OF DD
640:
650: 0368 A9 01
660: 036A 8D OB DD
670: 036D A9 00
680: 036F 8D OA DD
690: 0372 A9 05
700: 0374 8D 09 DD
710: 0377 A9 00
720: 0379 8D 08 DD
730:
740: 037C A9 84
750: 037E 8D OD DD
760:
770: 0381 A9 8C
780: 0383 AO 03
STA CRA
IDA CRB (
AND #$7F ;SET CLOCK TIME
STA CRB
LDA HOURS
STA TODSTD
LDA *MINUTES
STA TODMIN
LDA #SECONDS
STA TODSEC
LDA #TENTHS
STA TODIO
LDA CRB
ORA #$80 ;SET ALARM TIME
STA CRB
LDA #ALARM.HR
STA TODSTD
LDA *ALARM.MN
STA TODMIN
LDA #ALARM.SC
STA TODSEC
LDA #ALARM.10
STA TODIO
LDA #X10000100 ; ALARM
STA ICR iFREE NMI
LDA #<TEST
LDY #>TEST
113
Advanced Machine Language
790:
800:
810:
820:
830:
840:
850:
860:
870:
880:
890:
900:
910:
920:
930:
940:
950:
960:
970:
980:
990:
1000:
1010:
1020:
0385 80 18 03
0388 8C 19 03
038B 60
t
038C 48 TEST
038D 8A
038E 48
038F 98
0390 48
0391 AC 00 DO
0394 98
0395 29 04
0397 00 03
0399 4C 56 FE
039C A9 02 ALARM
OSgB 80 20 00
03A1 68
03A2 A8
03A3 68
03A4 AA
03A5 68
03A6 40
STA NMI
STY NMI+l
RTS
PHA
TXA
PHA
TYA
PHA
LOY ICR
TYA
AND #X100
BNB ALARM
JMP CONTNMI
;NEH NMI VECTOR
;SAVE REGISTERS
LDA
STA
PLA
TAY
PLA
TAX
PLA
RTI
*RED
BORDER
; ALARM BIT SET?
:YES
; BORDER COLOR TO
RED
]033C-03A7
NO ERRORS
The program first defines the addresses of the real-
time clock and the control register in the CIA 2, Then the
clock time is set to 12 o'clock and the alarm time to 12
o'clock and 5 seconds. The program first sets the real-time
clock to 60 Hz so that the clock runs correctly. Then bit 7
114
Advanced Machine Language
in control register B is cleared in order to inform the CIA
that we want to input the clock time, which we proceed to
do. Now we set bit 7, program the alarm time, and enable the
alarm NMI in the interrupt control register. Bit 2 as well
as bit 7 must be set in order to do this. Finally, we must
set the NMI vector to our new routine and the initialization
is completed.
The actual NMI routine does not have much to do. First
the registers are saved on the stack, then the interrupt
control register is read and bit 2 checked. If the bit was
set, the alarm time was reached. We respond by setting the
border color of the screen to red. The registers are res-
tored and control is returned to the interrupted program. If
the NMI was not generated by the alarm time, we jump to the
NMI routine in the kernal. There a check is made to see if
the STOP key was pressed in addition to the RESTORE key
which generated the interrupt. If this test is positive, a
warm start is executed.
Naturally, you can change the action which occurs when
the alarm time is reached. For example. your routine could
sound a tone through the sound chip. You should also add an
easy way of setting the clock and alarm times. The real-time
clock is very accurate over a long period of time because it
runs in synchronization with the AC power lines.
115
Advanced Machine Language
2.6 Using the tiaer
Each CIA contains two 16-bit timers. An interrupt can
be generated when the timer times out. These timers are used
heavily by the operating system and are decremented by one
with each system clock pulse. If the value zero is reached,
the corresponding bit in the interrupt request register is
set and — if the mask in the interrupt control register
permits it— an IRQ or NMI is generated. The American version
of the Commodore 64 has a clock frequency of approximately
1.02 MHz, resulting in a clock period of about ,98 micro-
seconds or close to 1 microsecond. Because the timer can be
loaded with a 16-bit value, times up to 65,535 clock periods
or approximately 65 milliseconds (about a fiftieth of a
second) can be attained. Timer A of CIA 1 is loaded with
$4295 or 17045, for example, which corresponds to one six-
tieth of a second. European PAL versions have a clock freq-
uency of 985 KHz, resulting in a clock period of 1.015
microseconds. The timer is loaded with the value $4025 or
16421, which corresponds to one sixtieth of a second at the
slower speed.
There are various operating methods for using the timer
such as the "one shot" and "continuous" modes. In the one-
shot mode the timer counts down only once from the initial
value to zero and then stops. In the continuous mode, the
timer is automatically reloaded with the starting value and
started again when it times out. In addition to generating
an interrupt, the timer can also generate a pulse on the
user port after time-out. This could be used as the clock
signal for a peripheral device. In addition, the timers can
be used as counters. In this mode, the system clock does not
do the decrementing. Instead, an external signal causes the
116
Advanced Machine Language
timer to be decremented. One can also couple the timers. One
timer counts the number of times the other reaches zero.
This allows the two to be used as a 32-bit timer. so that
times up to 2^32 clock cycles or about 4,360 seconds (1 hour
and 12 minutes) can be recorded.
At the close of our chapter on interrupt programming,
we want to write a machine language program that allows us
to control BASIC subroutines with interrupts. We will learn
something about the use of the timers as well as the opera-
tion of the BASIC interpreter.
He will introduce a new BASIC command which allows us
to execute a normal BASIC subroutine when a certain time has
elapsed. First a bit of background information.
The BASIC interpreter uses a main loop when executing a
BASIC program to analyze and execute each statement. After
each statement, a check is made to see if the STOP key was
pressed. If it was pressed, the main loop is exited and
control returns to the direct mode. The reading of the STOP
key occurs via a jump vector. We can change this vector so
that it points to a new routine. In this new routine we can
check to see if the condition for executing our interrupt
program has been met. In other words, to see if the timer
has timed out. In order to recognize this, an interrupt
routine sets a flag based on the state of the timer, which
can then be read by the previous routine.
The new BASIC command specifies which BASIC routine is
to be executed after an interrupt. An additional parameter
specifies the time at which the interrupt should be genera-
ted. The command looks like this.
117
Advanced Machine Language
!GOSUB 1000,100
The exclamation point is used to differentiate the new
conmand froa the normal GOSUB command. The 1000 is the first
line number of the subroutine and the 100 is the time at
which the interrupt will be generated. The time increments
are fiftieths of a second. We load a timer with this value
(for one fiftieth of a second). We load the second value
(the second parameter of the command) into the next timer,
using the two of them together as a 32-bit timer. We can
then program times from a fiftieth of second to 65535 fif-
tieths of a second, which is 0.02 to 1311 seconds (21 min-
utes and 51 seconds).
Our program consists of three routines in addition to
the initialization. The first modifies the BASIC interpreter
so that it understands our new command. The second routine
checks (after each statement) to see if the time-out flag is
set and if so, branches to the BASIC subroutine. The third
routine is the interrupt (actually NMI) routine which sets
the flag for the second routine after the timer times out.
100: CCOO .OPT PI
110: CCOO .SYM 2
130:
140:
INTERRUPT ROUTINE FOR BASIC
150:
160:
0308
EXEC
$308
; EXECUTE VECTOR
FOR STATEMENT
;NNI VECTOR
;ST0P VECTOR
170:
0318
NMI
$318
180:
0328
STOP
$328
190:
118
Advanced Machine Language
200:
210:
220:
230:
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
360:
370:
380:
390:
400:
410:
420:
430:
440:
450:
DDOO
DD04
DD06
DDOD
DDOE
DDOF
FE66
4FB0
0014
0015
005F
0039
0073
0079
007A
008D
AF08
A8E3 '
B248
A7AE
A96B
A613
AEFD
A7E7
CIA2
TXMERA
TIMERS
ICR
CRA
CRB
CONTNMI =
I
TIME =
LO
HI =
LINEADDR =
LINENO
CHRGBT
CHRGOT
TXTPTR
GOSUB
SYNTAX
UNDEFD
ILLQUAN =
INTER =
GETLIN
GETADDR =
CHKCOM
EXECOLD =
$DD00
CIA2+4
CIA2-t-6
CIA2+13
CIA2+14
CIA2+15
$FE56
20400
$14
LO+1
$5F
$39
$73
CHRGET+6
CHRGOT+1
$8D i
$AF08 ;
$A8E3 ;
$B248 ;
$A7AE
$A96B
$A613
$AEFD
$A7E7
; TIMER A
; TIMER B
; INTERRUPT CON-
TROL REGISTER
; CONTROL REG-
ISTER A
; CONTROL REG-
ISTER B
; CONTINUE OLD NNI
;=20 MILLISECONDS
; LINE NUMBER LO
; ADDRESS OF BASIC
LINE
; RUNNING LINE
NUMBER
GOSUB TOKEN
SYNTAX ERROR
UNDEF'D STATEMENT
ERROR
ILLEGAL QUANTITY
ERROR
INTERPRETER LOOP
GET LINE NUMBER
SEARCH LINE
TEST COMMA
EXECUTE STATEMENT
119
Advanced Machine Language
460:
AD8A
FRMNUM
$AD8A
;GET NUMERICAL
VALUE
470:
B7F7
INTEGER
$B7F7
;AND CONVERT TO
INTEGER
480:
A3FB
TESTSTACK=
$A3FB
; CHECK FOR SPAC
IN STACK
490:
F6ED
riSb LULU
$F6ED
; CHECK STOP KEY
500:
FB47
UUT/\T n
$FB47
;OLD NMI VECTOR
510:
520:
CCOO
$CCOO
530:
CCOO
A9
10
INIT
IDA
#<TBSTSTAT
540:
CC02
AO
CC
T n V
JUll I
#>TESTSTAT
550:
CC04
8D
08
03
O X A
la Auv
■ROUTINE FOR
560:
CC07
8C
09
03
Oil
570:
CCOA
A9
00
LDA
580:
CCOC
8D
F7
CC
o L n
FLAG
; ERASE rLAu
590:
CCOF
60
RTS
600:
!
610:
CCIO
20
73
00
T1ZQTQT A T
mo 1 o 1 A 1
«i on
CHR6ET
;GBT NEXT CHAR-
ACTER
620:
CC13
C9
21
#"!"
630:
CC15
FO
06
TST60SUB
640:
CC17
20
79
00
JSR
CHRGOT
; REPLACE FLAGS
650:
CCIA
4C
B7
A7
JMP
BXBCOLD
;AND CONTINUE
NORMAL
660:
t
670:
CCID
20
73
00
TSTGOSUfi
JSR
CHRGET
;NEXT CHARACTER
680:
CC20
C9
8D
CMP
*GOSUB
;GOSUB CODE?
690:
CC22
FO
03
BEQ
OK
; YES
700:
CC24
4C
08
AF
JMP
SYNTAX
; SYNTAX ERROR
710:
CC27
20
73
00
OK
JSR
CHRGET
;NEXT CHARACTER
720:
CC2A
FO
68
BEQ
IRQOFF
;LINE END, THEN
120
Advanced Machine language
SWITCH IRQ ADD
730:
CC2C
20
6B
A9
- JSR
GETLIN ;
GET LINE NUMBER
740:
CC2F
20
13
A6
JSR
GETADDR
;GET LINE ADDRESS
750:
CC32
BO
03
BCS
FOUND ;
FOUND?
760:
CC34
4C
E3
A8
JMP
UNDEFD ;
NO, UNDEF'D
STATEMENT ERROR
770:
CC37
A5
5F
FOUND
LDA
LINEADDR
;LINB ADDRESS
780:
CC39
Eg
01
SBC
#1 ;
MINUS 1
790:
CC3B
8D
F8
CC
STA
LINESTR
;SAVE
800:
CC3E
A5
60
LDA
LINEADDR+1
810:
CC40
B9
00
SBC
#0 ;
HIGH BYTE
820:
CC42
8D
F9
CC
STA
LINESTR+1
830:
CC45
20
FD
AE
JSR
CWKCK FOR COMMA
840:
CC48
20
8A
AD
JSR
E icran ura i
NRXT VALUE
850:
CC4B
20
F7
B7
JSR
IMTfiufin
ivUnVISKX Lv
INTEGER
860:
CC4B
AS
14
LDA
LO
870:
CC50
05
15
ORA
HI i
LOW AND HIGH BYTE
ZERO?
880:
CC52
DO
03
BNE
OKI 1
;N0
890:
CC54
4C
48
B2
JMP
ILLQUAN
; ILLEGAL QUANTITY
ERROR
900:
CC57
A5
15
OKI
LDA
HI
910:
CC59
8D
07
DD
STA
TIMERB+1
920:
CC5C
A5
14
LDA
LO
iLOAD VALUE INTO
TIMER B
930:
CC5E
8D
06
OD
STA
TIMERS
940:
CC61
Ag
4F
LDA
#>TIME
;LQAP TIMER A
950:
CC63
8D
05
DD
STA
TIMERA+1
960:
CC66
A9
BO
LDA
#<TIME
;WITH 20MS
970:
CC88
80
04
DD
STA
TIMERA
980:
CC6B
A9
11
LDA
#X00010001 ; START TIMER A
990:
CC6D
8D
OE
DD
STA
CRA
121
Advanced Machine Language
1000: CC70 A9 51
1010: CC72 8D OF DO
1020: CC75 AD OD DD '
1030: CC78 A9 82
1040: CC7A 80 00 DO
1050: CC7D A9 C9
1060: CC7F AO CC
1070: CC81 80 28 03
1080: CC84 8C 29 03
1090: CC87 A9 BO
1100: CC89 AO CC
1110: CC8B 80 18 03
1120: CC8E 8C 19 03
1130: CC91 4C AE A7
1140: ;
1150: CC94 A9 7F IRQOFF
1160: CC96 80 00 00
1170: CC99 A9 ED
1180: CC9B AO F6
1190: CC90 80 28 03
1200: CCAO 8C 29 03
1210: CCA3 A9 47
1220: CCA5 AO FB
1230: CCA7 80 18 03
1240: CCAA 8C 19 03
1250: CCAO 4C AE A7
LDA #^01010001 ; START TIMER B
STA CRB iTRIGQERBD BY
TIMER A
LDA ICR ; ERASE ICR
LDA *X10000010 ;NMI FOR
TIMER B
STA ICR ; FREE
LDA *<TESTTIMB
LDY *> TESTTIME
STA STOP ;GET STOP VECTOR
STY STOP+1
LDA #<NMIROOT
LDY #>NMIROUT
STA NMI ;SBT NMI VECTOR
STY NMI+1
JMP INTER J TO INTERPRETER
LOOP
LDA #«01111111
STA ICR ;ALL INTERRUPTS
OFF
LDA #<TESTOLD
LDY #>TESTOL0
STA STOP ;ST0P VECTOR TO
OLD VALUE
STY STOP+1
LDA *<NMI0LD
LDY #>NMIOLD
STA NMI ;NMI VALUE TO OLD
VECTOR
STY NMI+1
JMP INTER ;T0 INTERPRETER
LOOP
122
Advanced Machine Language
1260:
1270:
CCBO
48
NMIROUT
PHA
1280:
CCBl
8A
TXA
1290:
CCB2
48
PHA
1300:
CCB3
98
TYA
1310:
CCB4
48
PHA
1320:
CCB5
AC
OD
DD
LDY
ICR
1330:
CCB8
98
TVA
1340:
CCB9
29
02
AND
#X10
; TIMER B TIMED
OUT?
1350:
CCBB
DO
03
BNE
TIMEOUT
; YES
1360:
CCBD
4C
56
FE
JMP
CONTNMI
; OTHERWISE NORMAL
NMI
1370:
1380:
CCCO
EE
F7
CC
TIMEOUT
INC
FLAG
;SET FLAG
1390:
CCC3
68
PLA
1400:
CCC4
A8
TAY
1410:
CCC5
68
PLA
1420:
CCC6
AA
TAX
1430:
CCC7
68
PLA
1440:
CCC8
40
RTI
1450:
>
1460:
CCC9
AD
F7
CC
TESTTINE
LDA
FLAG
;FLA6 SET?
1470:
CCCC
DO
03
BNE
TIMEIRQ
; YES
1480:
CCCE
4C
ED
F6
JMP
TESTOLD
1490:
t
1500:
CCDl
CE
F7
CC
TIMEIRQ
DEC
FLAG
; ERASE FLAG AGAIN
1510:
CCD4
68
PLA
1520:
CCDS
68
PLA
fRETURN ADDRESS
FROM STACK
1530:
CCDS
A9
03
LDA
#3
1540:
CCD8
20
FB
A3
JSR
TESTSTACK ; STILL ENOUGH
STACK SPACE
123
Advanced Machine Language
1550:
CCDB
AS
7B
LDA
TXTPTR+1
1560:
CCDD
48
PHA
1
CHR6ET POINTER
TO STACK
1570:
CCDE
A5
7A
LDA
TXTPTR
1580:
CCEO
48
PHA
1590:
CCEl
AS
3A
LDA
LINENO+1
1600:
CCE3
48
PHA
1
ACTUAL LINE
NUMBER ON STACK
1610:
CCE4
AS
39
LDA
LINENO
1620:
CCE6
48
PHA
1630:
CCE7
A9
8D
LDA
#GOSUB
1640:
CCE9
48
PHA
GOSUB CODE ON
STACK
1650:
CCEA
AD
F8
CC
LDA
LINESTR
1660:
CCED
85
7A
STA
TXTPTR ;
ADDRESS OF SUB-
ROUTINE
1670:
CCEF
AD
F9
CC
LDA
LINESTR+1
1680:
CCF2
85
7B
STA
TXTPTR+1
1690:
CCF4
4C
Bl
A7
JMP
INTER+3
;T0 INTERPRETER
LOOP
1700:
t
1710:
CCF7
FLAG
*=
*+l
1720:
CCF8
LINESTR
* =
«+2
]CCOO-CCFA
NO ERRORS
SYMBOL-TABLE:
LINESTR
CCF8
FLAG
CCF7
TIMEIRQ
CCDl
* TESTTIME
CCC9
TIMEOUT
CCCO
NMIROUT
CCBO
IRQOFF
CC94
OKI
CC57
FOUND
CC37
OK
CC27
TSTGOSUB
CCID
TESTSTAT
CCIO
124
Advanced Machine Language
INIT
CCOO
NMIOLD
FE47
TESTOLD
F6ED
TESTSTAC
A3FB
INTEGER
B7F7
FRMNUM
AD8A
EXECOLD
A7E7
CHKCOM
AEFD
GETADDR
A613
GETLIN
A96B
INTER
A7AE
ILI.QUAN
B248
UNDEFD
A8E3
SYNTAX
AF08
GOSUB
008D
TXTPTH
007A
CHRGOT
0079
CHRGET
0073
LINENO
0039
LINEADDR
005F
HI
0015
LO
0014
TIME
4FB0
CONTNMI
FE56
CRB
DDOF
CRA
DDOB
ICR
DDOD
TIMERB
DD06
TIMERA
DD04
CIA2
DDOO
STOP
0328
NMI
0318
EXEC
0308
45 SYMBOLS DEFINED
Before we come to the detailed description of the
program, here is a small demonstration program.
100 SYS 52224 : REM INITIALIZE EXPANSION
110 'GOSUB 200,50
120 1 = 1+1 : PRINT I : IF KlOO GOTO 120
130 ! GOSUB
140 END
200 J=J+1 : PRINT "IRQ CALL #" J : RETURN
When you start this program with RUN, the new command
is added by the SYS in line 100. Line 110 defines the sub-
routine at line 200 as the interrupt program, which is
executed every second (50 fiftieths). The actual main prog-
125
Advanced Machine language
ram is in line 120 and outputs the number fron 1 to 100.
When this loop is ended, the interrupt routine is switched
off by !60SUB without any parameters and the program ends.
The interrupt routine is at line 200. It displays a running
count of the number of calls before returning to the main
program with RETURN.
If you run the program, numbers from 1 to 100 will be
printed, but the output will be interrupted five times with
the message
IRQ CALL * 1
through
IRQ CALL * 5
If you change the second parameter in line 110, you can
set the frequency at which the subroutine is called. Values
from 1 to 65535 are allowed. The smaller the value is, the
more often the interrupt routine will be called. The time
required to execute the BASIC interrupt routine may not be
longer than the time between calls, otherwise the interrupt
routine will interrupt itself and the BASIC stack will
overflow. For example, if your replace line 110 with
110 !60SUB 200,1
you will receive the following output:
1
IRQ CALL # 1
IRQ CALL #2
126
Advanced Machine language
IRQ CALL # 22
IRQ CALL #23
?OUT OF MEMORY ERROR IN 200
Now to description of the machine language prograa.
Constants are defined in lines 100 to 500. These con-
cern the NMI and BASIC vectors. Then follow the registers
in the CIA 2 which are necessary for the tiner interrupt.
Line 290 defines our time increment. After this are BASIC
addresses from the zero page as well as error messages and
ROM addresses used by the BASIC interpreter. The initializa-
tion is performed in lines 520 to 590. Here the vector which
points to the routine for decoding and executing a BASIC
statement is redirected to our own routine. This routine
gets the next character from the BASIC text and compares it
with the exclamation point. If this character is not found,
the original values of the flags are restored with the
CHR60T routine and a jump is made to the point in the inter-
preter where statements are normally processed. If, on the
other hand, an exclamation point is found, we get the next
character and check if it is the code for QOSUB. If not,
then we output "SYNTAX ERROR." If so, then it is our new
command. The next character is fetched. If it is the end of
the line, a branch is made to the routine which disables the
Interrupt and resets the vectors to their original values.
Otherwise the line number is determined and its address
obtained. After a check is made to see if this line really
exists (signaled by a set carry flag), the line address is
decremented by one and saved. Now a test can be made for the
comma and the second parameter fetched. The second parameter
127
Advanced Machine Language
deteriaifies the duration between interrupts. If it is not
zero, timer B is loaded with it. Timer A is loaded with the
value for a fiftieth of a second and both timers are start-
ed. Timer B is programmed such that it is decremented each
time timer A reaches zero (times out). The NMI for timer B
is then enabled by writing the corresponding bit pattern
into the control register. Finally, the STOP and NMI vectors
are set to the new routines before we jump back to the
interpreter loop.
From line 1150 to 1250 you find the routine which turns
the interrupt off following a !60SUB command without para-
meters. It also sets the vectors back to the original val-
ues. The actual NMI routine is perfomed by lines 1270 to
1390. The registers are first saved and the status of timer
B is tested by reading the interrupt control register, to
see if the timer generated the NMI. If this was the case, a
flag is set and the NMI routine exited. Otherwise execution
branches to the normal NMI routine.
The most important subroutine, called by the BASIC
interpreter after each statement, is found at line 1410.
Here a check is made to see if the appropriate flag from the
NMI is set indicating that the time is up. If the test is
negative, a branch is made to the normal routine which
checks the STOP key. If the time was up, the flag is cleared
and the actual return address is pulled from the stack. The
BASIC 60SUB command is then imitated. After the program
determines that there is enough room left on the stack, the
pointer to the BASIC text as well as the current line number
are saved on the stack. In order to distinguish this from a
FOR-NBXT loop which also places its parameters on the stack,
the GOSUB code is pushed onto the stack. Next the address of
128
Advanced Machine Language
the subroutine is determined as saved by the definition,
loaded into the BASIC text pointer and a branch is again
made to the interpreter loop. The BASIC interpreter executes
the subroutine and can correctly return to the interrupted
program when it encounters the RETURN command.
The program ends with the definition of two variables.
The .SYM pseudo-op in line 120 produces the symbol table
shown at the end of the listing which includes all of the
symbols used together with their values.
This new command offers you possibilities in BASIC
which could previously be attained only in machine language.
You can now execute time-controlled subroutines in BASIC
with a time span from 20 milliseconds to 21 minutes to
choose from. This is one example of interrupt control from
within BASIC. To illustrate the routine, here is a program
which flashes the screen by exchanging the background and
border colors.
100 SYS 52224
110 Fl = 53280 : F2 = Fl + 1
120 !GOSUB 1000,30
130 FOR 1=1 TO 1000 : PRINT I, : NEXT
140 !60SUB : END
1000 A=PEEK(F1) : POKE F1,PEEK(F2) : POKE F2,A : RETURN
The BASIC interrupt routine should always be deact-
ivated with !GOSUB before the end of the program. If you
later try to list or save a program with the interrupt
routine active, it will interrupt this process because these
routines check for the STOP key.
129
Advanced Machine Language
The next example program displays the Commodore 64 's
character set in normal and reverse and then switches, on
interrupt, between the standard text representation and the
extended color node. This is done by setting bit 6 in regis-
ter 17 of the video controller. In this mode only 64 char-
acters instead of 256 can be displayed. The upper two bits
of the screen memory now serve to select one of four dif-
ferent background colors for each character. These colors
are placed in registers 33 to 38 of the video controller
(addresses 53281 to 53284).
100 SYS 52224
110 !GOSUB 170,25
120 X=18
130 PRINT CHR$(X) ; : X=X+128 AND 255
140 FOR 1=32 TO 127: PRINT CHR$( 1} ; : NEXT
150 FOR 1=160 TO 255: PRINT CHR$(I) ; :NEXT
160 PRINT:GOTO130
170 A=PEEK(53248+17):P0KK53248+17, (A0R64)ANDN0T(AAND64)
180 RETURN
130
Advanced Machine Language
SBCTION 3 Beyond BASIC
3.1 Kernal and BASIC extensions
One advantage that the CoBmodore 64 has over its "big"
brothers, the CBM 8032 and 8096 is that the BASIC inter-
preter and operating system kernal can be easily "expanded"
witli your own customized routines.
By expand we mean that we can extend the capabilities
by adding new or enhanced commands to BASIC. It is no longer
necessary to access each new command with PEEK, POKE, or
SYS. There are two ways to do this.
Because the entire address space of the Commodore 64 of
64K is equipped with RAN, you can easily make changes in the
BASIC and operating system by copying the BASIC interpreter
and/or the kernal ROM into the RAM lying at the same ad-
dress. Then you can make the desired changes and "switch on"
this RAM version of BASIC by means of the processor port at
address 1. This method has both advantages and disadvantages
compared to the method described later.
The advantage of this method is that you have complete
freedom in making changes. This freedom is so extensive that
a completely different language can be used in place of
BASIC, or a completely new operating system can be constr-
ucted. This RAM area is otherwise often used for such things
as graphics storage. The disadvantage of this method lies in
that this RAM area is no longer available for other pur-
poses. A variant of this method is the use of one or two
BPROMs in the address range from $8000 to $9FFF or from
131
Advanced Machine Language
$8000 to $BFFF which contains a BASIC extension, another
language, or a user-specified program. A cartridge in the
cartridge slot is necessary for this, however.
A second method does not require additional ROM but
rather uses entry points in the system software in order to
modify the most important functions. These key positions are
accessed via so-called jump vectors which can be changed by
the user. An indirect jump instruction used at this point.
For example
JMP (VECTOR)
The low and high bytes of the actual jump address are
stored at the address vector. These vectors are initialized
when the computer is turned on and usually point directly
behind the indirect jump command in the BASIC interpreter.
If we want to change a certain function, we write our own
routine and change the appropriate jump vector so that it
points to our new routine. The principle is similar to that
which we learned for interrupt vectors.
The following table gives information concerning what
bit pattern must be written to address 1 in order to get the
appropriate memory configuration when using the "HAM met-
hod":
132
Advanced Machine Languace
Bit
2
1
dec
tAOOO - $BFFF
iDOOO - $DFFF
4E000 - JFI
1
1
1
7
BASIC
I/O
KERNAL
1
1
6
RAN
I/O
KERNAL
1
1
5
RAM
I/O
RAM
1
4
RAN
RAN
RAM
1
1
3
BASIC
CHAR GEN
KERNAL
1
2
RAN
CHAR GEN
KERNAL
1
1
RAN
CHAR GEN
RAM
RAN
RAN
RAM
This table contains all possible combinations for the
memory configuration. Combinations 4 and have the same
result; the complete address space is switched to RAM. You
can see from the table that BASIC can be exchanged for RAM
independently, but the kernal RON must be switch out to-
gether with the BASIC HON. This should be noted if the
kernal is to be replaced. The address area at $DOOO-$DFFF
has three functions: it is the I/O area, which is divided as
follows :
$D000
- $D3FF
VIC 6567
$D400
- $D7FF
SID 6581
$D800
- $DBFF
color RAN
$DCOO
- $DCFF
CIA 1 6526
$DDOO
- $DDFF
CIA 2 6526
$DEOO
- $DEFF
I/O 1 for expansion
$DFOO
- $DFFF
I/O 2 for expansion
In addition, the character generator can be addressed at
this address. Third, this area is allocated with RAN which
can only be addressed when the entire memory is switched to
RAN.
133
Advanced Machine Language
3.2 The BASIC vectors
The BASIC interpreter has six vectors which aake it
possible t
o add new
routines. These vectors are
placed in
page 3 and
have the
following use:
Vector
Address
Sitfnif icance
$0300/$0301
$E38B
BASIC warn start and error
entry
point
$0302/$0303
$A483
input delay loop
$0304/$0305
$A57C
conversion to interpreter code
$0306/$0307
$A71A
convert interpreter code to
text
$0308/$0309
$A7E4
execute BASIC coanand
$030A/$030B
$AE86
evaluate BASIC expression
With the help
of these 6 vectors you have
an easily
accessible
way of changing the BASIC interpreter
. We
will
become acquainted with the significance of each vector and
use then for extensions and enhancenents .
In order to draw the greatest usefulness from this
section, you may want to consult the ROM listing of the '84
found in The Anatomy of the Connodore 64 as we go along.
This allows you to trace exactly what happens in the BASIC
interpreter.
The warn start and error vector $300/$301
This vector is used when the END of the program or an
error is encountered. If an error occurs, the X register
contains the error number. These numbers range from 1 to 29
and have the following meaning:
134
Advanced Machine Language
No. Error message
1
TOO MANY FILES
2
FILE OPEN
3
FILE NOT OPEN
4
FILE. NOT FOUND
S
DEVICE NOT PRESENT
6
NOT INPUT FILE
7
NOT OUTPUT FILE
8
MISSING FILENAME
9
ILLEGAL DEVICE NUMBER
10
NEXT WITHOUT FOR
11
SYNTAX
12
RETURN WITHOUT GOSUB
13
OUT OF DATA
14
ILLEGAL QUANTITY
15
OVERFLOW
16
OUT OF MEMORY
17
UNDEF'D STATEMENT
18
BAD SUBSCRIPT
19
REDIM'D ARRAY
20
DIVISION BY ZERO
21
ILLEGAL DIRECT
22
TYPE MISMATCH
23
STRING TOO LONG
24
FILE DATA
25
FORMULA TOO COMPLEX
26
CAN'T CONTINUE
27
UNDEF'D FUNCTION
28
VERIFY
29
LOAD
135
Advanced Machine Language
Error messages from 1 to 9 are input/output related
errors and are Issued by the operating system (kernel).
Errors 10 to 29 are generated by the BASIC interpreter. If
an error is recognized by the BASIC interpreter, the X
register is loaded with the error number and a jump is made
to address $A437 by way of the indirect Jump JMP ($0300). If
the program is ended with END as normal, however, the X
register is loaded with a negative value ($80) in order to
distinguish it from an error message. This is checked in the
error routine, the error output bypassed, the message
"READY." displayed, and a branch made to the input-wait
loop.
We can use the error vector for a variety of purposes.
For one, we could change the text of the error messages, or
prevent the program from breaking off when an error is
discovered, but to branch to a specified BASIC line where
the error can be caught or perhaps corrected. Some enhanced
versions of BASIC have a command for this purpose such as:
ON ERROR GOTO . . .
Such a command can, for example, be used to catch errors
generated by peripheral devices.
The input-wait loop $302/$303
When the computer displays the READY. prompt after END
or an error message, it goes to the warm-start vector at
$300. Then it Jumps to the vector $302/$303. In this rou-
tine, the computer waits for the input of a line terminated
by the <RETURN> key.
136
Advanced Machine Language
This line is checked to make sure that it is not longer
than 88 characters (the length of the BASIC input buffer
located from $200 to $258.) If this length is exceeded, the
error message "STRING TOO LONG" is displayed. The first
character of the inputted line determines how the line will
b4 treated. If the first character is a digit, the inter-
preter assumes that we want to enter a new BASIC line. In
this case, the entire line number is read and a check is
made to see if this line exists. If so, the old line is
deleted from the program. If nothing follows the line
number, then the line is to be simply deleted and a branch
is made back to the start of the loop. If additional text
follows the line number, this text is converted to inter-
preter codes, and the program line is inserted into the
BASIC text, and a branch is again made to the start of the
loop.
If the first character entered was not a digit, the
line is interpreted as a BASIC command in the direct mode.
The line is converted to interpreter codes and a branch is
made to the place in the interpreter where a BASIC command
is executed.
We can also use this vector to extend or enhance BASIC.
For example, it is possible to take program input from a
sequential disk file or from the user port, from another
computer connected there, instead of the keyboard. This
greatly simplifies the transfer of BASIC programs from other
computers. The slow and error-prone typing-in of listings is
no longer necessary. With direct coupling of two computers,
the sending computer need only list Its program over the
interface. The RS 232 is best suited for this purpose since
most computers have this interface available to them.
137
Advanced Machine Language
An additional application of this vector is the AUTO
command. This command eases the input of programs by auto-
matically placing the next line number at the start of the
line and positioning the cursor behind it.
Conversion to interpreter codes $304/$305
As you probably know, a program line is not saved as it
was entered. Instead, each command word is shortened to a
single-byte value called a token. This has two advantages
over storing the entire text of that word. First, it saves
memory. Instead of 5 bytes for the word "PRINT" only one
byte is require for the token. The second advantage is
noticeable during program execution. When the BASIC inter-
preter is executing a program and comes across a token, it
can immediately execute the appropriate command. If the
command were saved in text (ASCII) form, the complete word
would have to be read. Then the interpreter would have to
read through its command table and see if the word is pre-
sent in its table as a command word. The program would take
considerably longer to run without tokens. If, on the other
hand, the program line is converted to tokens, this conver-
sion is only necessary once and not each time the command is
executed.
If we want to convert new commands to tokens, we can
change this vector. Our routine must then compare the word
read from the input with the table of the new command words.
If a new command is found, the command word is replaced by
its token in the program or command line.
138
Advanced Machine Language
Conversion of the interpreter code to text (ASCII) $306/$307
This vector perforins the opposite task of the one
above. If we want to list a program, we must convert the
tokens back into text. The token value is used as a pointer
in the command word table. This vector is used only by the
LIST command. We must change it when we use our own inter-
preter codes so that the new commands can be listed proper-
ly. An additional application is to change the operation of
the LIST command. We could for example make a listing more
readable by placing a space after each command word, or by
indenting loop structures. It is also possible to start a
new line for each new statement separated by a colon.
Execute a command $308/$309
This vector is one of the most important. It points to
the place in the interpreter where a BASIC command is exe-
cuted. Normally, this routine gets a character from the
BASIC text and check to see if it is a token. If the char-
acter is not a token, the interpreter assumes that it is an
assignment of the form "A = ..." and branches to the LET
command. If it is a token, its value is used as an index in
a table containing the BASIC commands. These commands are
executed as subroutines and after execution can branch back
to the start of the interpreter loop where the next state-
ment can be handled in the same way.
With the help of this vector one can easily add custom
BASIC commands to the interpreter. These can be designated
by a special character such as an exclamation point (!). We
can then check for this character in our routine and execute
the new command when found.
139
Advanced Machine Language
If we have added our own tokens for our new commands
using the previously described vector $304/$305, a special
character is no longer necessary. Instead, we can first
check for our new tokens and branch to the original routine
for executing commands if the new command Is not found.
Evaluate a BASIC expression $30A/$30B
This vector is to a function what the previous vector
was to a command. This vector is used when an element of an
expression is to be calculated. This element can be a num-
ber, a BASIC variable, or a function. If we want to add new
functions, we must add them using this vector. Numeric as
well as string functions can be handled. You must also
modify this vector if you save variables in other forms.
This allows such things as hex and binary constants.
100:
110:
120:
130:
140:
150:
160:
170:
180:
190:
200:
210:
220:
230:
033C
030A
AE8D
OOOD
0073
0079
BD7E
005D
.OPT PI
INPUT OF HEX AND BINARY NUMBERS
EXPRESSION
OLDVECT =
>
TYP
CHRGET
CHRGOT
I
ADODIGIT =
1
FLOAT
$30A ; VECTOR FOR EXP-
RESSION EVALUATION
$AE8D ;OLD ROUTINE
13
$73
CHRGET+6
; VARIABLE TYPE
$BD7E ;ADD ONE-BYTE
DIGIT TO FAC
$5D
; RANGE FOR FLOAT-
140
Advanced Machine Language
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
360:
370:
380:
390:
400:
410:
420:
430:
440:
450:
460:
470:
480:
490:
500:
EXP
*
OVERFLOW =
0061
B97E
033C
I
033C A9 47 INIT
033E AO 03
0340 8D OA 03
0343 8C OB 03
0346 60
1
0347 A9 00 TEST
0349 85 OD
034B 20 73 00
034E C9 24
0350 FO OA
0352 C9 25
0354 FO 41
1
0356 20 79 00
0359 4C 8D AE
$61
ING POINT NUMBERS
; EXPONENT FROM FAC
$B97E ; OVERFLOW ERROR
*=
LDA
LDY
STA
STY
RTS
LDA
STA
JSR
CMP
BEQ
CMP
BEQ
JSR
JMP
828
#<TEST
#>TEST
EXPRESSION ;SET VECTOR
TO NEW ROUTINE
EXPHESSION+1
0350 20 8D 03 HEXNUMBERJSR
035F 20 73 00 GETNEXT JSR
0362 90 OB
0364 C9 41
BCC
CMP
#0
TYP ;TYPE FLAG TO
NUMERIC
CHRGET ;GET NEXT CHAR-
ACTER
#"$" ;HEX NUMBER?
HEXNUMBER
; BINARY NUMBER?
BINNUMBER
CHRGOT ; REPLACE FLAGS
OLDVECT ;AND GO TO OLD
EVALUATION
CLHFAC ; CLEAR FAC
CHRGET ;GET NEXT CHAR-
ACTER
DIGIT ;DIGIT
#"A"
141
Advanced Machine Language
510
0366
90
IF
BCC
END
520
: 0368
C9
47
PMP
vWr
530
: 036A
BO
IB
Di/O
AND
; GREATER THAN "F"
540
: 036C
38
SEC
550
: 036D
E9
07
SBC
#7
) lAim UfJfSiST INTO
ACCOUNT
560
: 036F
38
DIGIT
SEC
565: 0370
E9
30
#"0"
; CONVERT TO HEX
570
0372
48
nun
rHA
;SAVE CHARACTER
.580: 0373
A5
61
IDA
EXP
585
0375
FO
07
BEQ
STILLZEHO ;IS FAC STUL
ZERO?
590:
0377
18
600:
0378
69
04
ADC
#4
; EXPONENT + 4=>
NUMBER * 16
610:
037A
BO
OE
BCS
OVER
; NUMBER TOO LARGE!
620:
037C
85
61
STA
EXP
630:
037B
68
STILLZERCPLA
;GET DIGIT BACK
640:
037F
FO
DE
BEQ
GETNEXT
;ZERO, THEN ADD-
ITION UNNECESSARY
650:
0381
20
7E BD
JSR
ADDDIGIT
;ADD DIGIT TO
FAC
660:
0384
4C
5F 03
JMP
GETNEXT
670:
680:
690:
700:
710:
720:
730:
740:
0387 4C 79 00 END
i
038A 4C 7E B9 OVER
JMP CHRGOT
JMP OVERFLOW
038D A9 00 CLRFAC LDA
038F A2 OA
0391 95 SD LOOP
750: 0393 CA
LDX
STA
DEX
#0
#10
FLOAT, X ; CLEAR FLOATING
POINT AREA
142
Advanced Machine Language
760:
0394
10
FB
BPL
770:
0396
60
RTS
780:
1
790:
0397
20
8D
03
BINNUNBERJSR
800:
039A
20
73
00
GETBIN
JSR
810:
039D
C9
32
CMP
820:
039F
BO
E6
BCS
830:
03A1
C9
30
CMP
840:
03A3
90
E2
BCC
850:
03A5
E9
30
SBC
860:
03A7
48
PHA
870:
03A8
AS
61
LDA
880:
03AA
FO
04
BEQ
890:
03AC
E6
61
INC
900:
03AB
FO
DA
BEQ
910:
03B0
68
ZERO
PLA
920:
03B1
FO
E7
BEQ
930:
03B3
20
7E
BD
JSR
940:
03B6
4C
9A
03
JMP
LOOP
CLRFAC
CHRGET
#"2"
END
#"0"
END
#"0"
EXP
ZERO
EXP
OVER
; CLEAR FAC
;GET NEXT CHAR-
ACTER
; GREATER THAN "l"?
;LESS THAN "0"?
;FRON ASCII TO HEX
;IS NUMBER STILL
ZERO?
; DOUBLE NUMBER
;T00 LARGE?
GETBIN ; DON'T ADD ZERO
ADDDIGIT ;ADD DIGIT
GETBIN ;AND GET NEXT
DIGIT
1033C-03B9
NO ERRORS
This routine works in the same way as the subroutine
for processing decimal digits, but it is simpler and easier
to understand because no fractions or exponents need to be
taken into consideration. When you activate the program with
SYS 828, you can enter numbers in either hexadecimal or
binary format in addition to the usual decimal form. For
example:
143
Advanced Machine Language
? $FFFF returns 65535
? XlOlOlO returns 42
You are not limited to four digit hex numbers. The
entire range of floating point numbers is available. This
means that a hex number may have a maximum of 31 places. For
example
? $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
returns
2.12676479E+37
The entire value range cannot be used in a single
binary input line; a number of 78 binary digits has a value
of about 3E-I-23.
With this command expansion you can use hex and binary
numbers not only in PRINT statements but wherever decimal
numbers were previously necessary. This is particularly
interesting in connection with POKE, PEEK, and SYS commands.
The address $D000 for the video controller is somewhat
easier to remember that 53248. For example, sprite 3 can be
activated with
POKE $D015, PEEK($D015) OR JKIOOO
instead of
POKE 53248+21, PEEK(53248+21) OH 8
144
Advanced Machine Language
There are a few problems with the hex input. Enter
? $ABCDEF
and you will get a "SYNTAX ERROR." Why? If you look at the
number closely you may recognize that it contains the com-
mand word "DBF" for the definition of functions. Since the
interpreter first converts the input line into tokens, the
string "DEF" gets converted to the appropriate token and
our new function returns a SYNTAX ERROR. We can easily get
around this by adding a space:
? $ABCD BF
Now we get the correct value 11259375. It is possible to
insert the space because the CHRGET routine ignores spaces.
This is also the case for normal decimal numbers.
let us take a closer look at the operation of the
routine.
After the usual initialization which sets the vector to
our new routine, the flag denoting the variable type is
cleared (set to numeric) as per the interpreter routine. Now
the next character can be fetched and tested. If it is a
dollar or percent sign, with which hex and binary numbers
are designated, respectively, a branch is made to our new
routine. If this was not the case, the flags are reset with
CHRGOT and execution continues with the original evaluation
routine of the interpreter. We proceed as follows in the new
routine to convert a hex number:
First, the floating-point accumulator is cleared be-
cause we will construct our result in it. The next character
145
Advanced Machine language
is fetched and checked to see if it is a digit or a letter
from "A" to "F". If this condition is met, the character is
converted to the corresponding hex value; for example, "1"
becomes the value $01 and "A" becomes $0A. The value in the
floating-point accumulator are multiplied by 16, provided it
is not zero. He perform this multiplication in the simplest
and fastest way. Instead of calling a floating-point mult-
iplication routine. which takes at least a millisecond, we
can see that multiplying by 16 is the same as incrementing
the power of two by 4: 16 = 2^4. We therefore simply add
four to the FAC exponent, which takes only a few micro-
seconds. After we are satisfied that no overflow occurred,
we get the character just read and add it to the FAC. If the
number is zero, we can skip the addition. This process is
done in a loop until the CHRGET routine reads a character
which is not part of the number.
The conversion of a binary number follows the same
pattern and is even simpler. Here we simply increment the
exponent by one instead of multiplying by two. The addition-
al procedures are the same as those for converting the hex
numbers .
146
Advanced Machine Language
3.3 Structured Prograulng
Throughout this book we have examined the operation of
the BASIC interpreter, especially the execution of simple
commands. We have not examined the concept of programming
structures. The interpreter recognizes only two sets of
commands for structured programming:
GOSUB . . . RETURN
and
FOR ... NEXT
In order to make use of these structures, the inter-
preter must know where to jump when executing the RETURN
command after a GOSUB to a subroutine so that the main
program can continue as normal. With the NEXT command, the
end value and step size must be known in addition to the
address of the start of the loop so that the interpreter can
determine when to end the loop. The parameters required for
RETURN and NEXT could be stored at a predetermined place in
memory. But what happens if we want to nest several sub-
routines or loops?
Care must be taken to ensure that the parameters for
the last used structure (RETURN or NEXT) can be accessed.
What was stored last must be gotten back first. We are
familiar with this principle from the stack: LAST IN - FIRST
OUT. Therefore the BASIC interpreter simply uses the stack
to store the parameters of the program structures.
147
Advanced Machine Language
What data must be saved on the stack by a GOSUB com-
mand? First, the address following the GOSUB call must
certainly be saved. In addition. the current line number
Bust be placed on the stack so that it has the correct value
upon return. In order that one can later distinguish the
data for a GOSUB command from that of a FOB command. the
GOSUB identification code is also placed on the stack. A
complete data set on the stack looks like this:
Stack pointer
before GOSUB command > program pointer hi
program pointer lo
line number hi
line number lo
GOSUB code $8D
Stack pointer
after GOSUB command >
The GOSUB command thus requires 5 bytes of space on the
stack. Because the 6610 stack pointer is only 8 bits long,
it can address only one page, from $100 to $1FF. It is clear
then that subroutines cannot be nested to any desired depth.
A maximum of 256/5 = 51 nested subroutines are possible.
Since the stack is also used for other purposes as well,
fewer are actually allowed. Before the execution of a GOSUB
command, a subroutine is called which checks to see if
enough space is left on the stack. When calling this subrou-
tine, one half the number of required memory locations is
placed into the accumulator. This must be 3 for the GOSUB
command; therefore the subroutine tests for 6 bytes. If the
required space is not available, the message "OUT OF MEMORY"
is given. This message is unfortunately worded the same as
the message printed when the memory space for variables has
148
Advanced Machine Language
been used up. A message such as "STACK OVERFLOW" would be
more appropriate.
The BASIC interpreter has only the area from $013E to
$1FA at its disposal in the stack. The memory range from
$0100 to $0110 is used for converting floating point numbers
to strings and the space from $0111 to $013E is used for
error correction when reading from the cassette.
What happens during a RETURN command? First a check is
made to see if the top stack element is the code for GOSUB.
If this is not the case. the error message "RETURN WITHOUT
GOSUB" is given. Otherwise the next four bytes are fetched
from the stack and the parameters for line number and prog-
ram pointer are taken care of. The stack pointer now points
to the element to which it pointed before the GOSUB call. A
jump is made to the interpreter loop and the program execu-
tion automatically continues with the statement following
the GOSUB command.
The principle is similar for a FOR-NEXT loop, but
somewhat more complicated because of the number of para-
meters which must be temporarily stored. The required para-
meters are stored on the stack in the following order:
149
Advanced Machine Language
Stack pointer
before FOR coniaand > program pointer hi
program pointer lo
line number hi
line number lo
mantissa 4
mantissa 3
mantissa 2 TO value
mantissa 1
exponent
sign
mantissa 4
mantissa 3
mantissa 2 STEP value
mantissa 1
exponent
variable address hi
variable address lo
FOR code $81
Stack pointer
after FOR command >
You can see that a FOR-NEXT loop requires 18 bytes of
storage on the stack. The following happens with a NEXT
command: First a check is made to see if the top stack
element is the FOR code $81. If this is not the case, the
error message "NEXT WITHOUT FOR" is given. If a variable
follows the NEXT command, the address of the variable is
determined and compared with the variable address on the
stack. If they are the same or there is no variable name
given, the variable value is placed in the FAC and the STEP
value from the stack is added. This value is saved as the
ISO
Advanced Hachlne Language
new variable value and can be conpared with the end value on
the stack. The sign of the STEP value can determine whether
the loop will be ended or not. If the loop can be ended,
the stack pointer is incremented by 18 in order to remove
the parameters from the stack and a jump made to the inter-
preter loop where the next statement can be executed. If, on
the other hand, the end value was not reached, the line
number and program counter are taken from the stack. The
stack pointer remains unchanged however, so that the data
remain for the next NEXT command.
If a variable name whose address is not saved on the
stack follows the NEXT command, the stack pointer is inc-
remented by 18 to see if another FOR-NBXT data set is pre-
sent on the stack. This automatically takes care of nested
loops .
With this knowledge we can add a new structure to
BASIC. If you have done any programming in Pascal, you are
probably acquainted with the REPEAT. . .UNTIL loop. This is a
program structure which runs until the end criterium is met.
For example
REPEAT
1=1+1
UNTIL 1=10
Here the loop is executed until the end condition of
1=10 is fulfilled. This structure can be used for a variety
of purposes. As with the FOR-NEXT loop, the contents of the
loop are executed at least once. Waiting for a key press can
also be accomplished with this loop.
151
Advanced Machine Language
REPEAT : GET A$ : UNTIL A$<>""
or sinpler
REPEAT : UNTIL PEEK(197)<>64
Here the computer waits until the meiaory location 197 con-
tains a value other than 64, indicating that a key was
pressed.
The following machine language program implements this
structure In BASIC.
100:
033C
.OPT
PI
120:
:
130:
;REPEAT-0NTIL
LOOP
140:
150:
0308
COMMAND =
$308
; EXECUTE VECTOR
FOR COMMAND
160:
1
170:
A7E7
CMD.OLD =
$A7E7
;OLD ROUTINE
180:
0022
ADDR
$22
; ADDRESS FOR
ERROR MESSAGE
190:
0039
LINENO
$39
; ACTUAL LINE
NUMBER
200:
0073
CHRGET
$73
210:
0079
CHHGOT
CHRGET-t-6
220:
007A
TXTPTR
CHRGOT+1
230:
0100
STACK
$100
; PROCESSOR STACK
240:
A445
ERROR
$A445
; OUTPUT ERROR
MESSAGE
250:
f
260:
A3FB
TESTSTACK=
$A3FB
;TEST FOR SPACE
152
Advanced Machine Language
270:
280:
290:
300:
310
320
330
340
350
360:
370:
380:
AD8A
A7AE
AF08
A906
FRMNUM
INTER
SYNTAX
NEXTSTAT
033C
033C A9 47
033E AO 03
0340 80 08 03
0343 8C 09 03
0346 60
INIT
*=
LDA
LDY
STA
IN STACK
$AD8A ;GET NUMERICAL
EXPRESSION
$A7AE ; INTERPRETER LOOP
$AF08 ; SYNTAX ERROR
$A906 ; SEARCH FOR NEXT
STATEMENT
828
#<TEST
#>TEST
COMMAND
J VECTOR TO NEW
ROUTINE
STY COMMAND+1
RTS
390:
0347
20
73
00
TEST
JSR
CHR6ET
;GET NEXT CHAR-
ACTER
400:
034A
C9
21
CMP
#" ! "
410:
034C
FO
06
BEQ
NEWCMD
;NEW COMMAND?
420;
1
430:
034E
20
79
00
JSR
CHRGOT
; REPLACE FLAGS
440:
0351
4C
E7
A7
JMP
CMD.OLD
;AND EXECUTE OLD
COMMANDS
450:
t
460:
0354
20
73
00
NEHCMD
JSR
CHR6ET
;NEXT CHARACTER
470:
0357
C9
52
CMP
#"R"
; REPEAT COMMAND
480:
0359
FO
07
BEQ
REPEAT
490:
035B
C9
55
CMP
#"U"
; UNTIL COMMAND
500:
035D
FO
24
BEQ
UNTIL
510:
035F
4C
08
AF
SYNERR
JMP
SYNTAX
; OTHERWISE SYNTAX
ERROR
520:
153
Advanced Machine language
530:
0362
20
73
00
REPEAT
JSR
CHRGET
; POINTER TO NEXT
CHARACTER
540:
0365
A9
03
LDA
#3
550:
0367
20
FB
A3
JSR
TESTSTACK ; ENOUGH SPACE
IN STACK?
560:
036A
20
06
A9
JSR
NEXTSTAT
; SEARCH FOR
NEXT STATEMENT
570:
036D
18
CLC
580:
036E
98
TYA
; OFFSET TO NEXT
COMMAND
590:
036F
65
7A
ADC
TXTPTR
; ADD
600:
0371
48
PHA
;AND ONTO STACK
610:
0372
AS
7B
LDA
TXTPTR+1
620:
0374
69
00
ADC
#0
630:
0376
48
PHA
640:
0377
A5
39
LDA
LINENO
; LINE NUMBER
660:
0379
48
PHA
;0N STACK
660:
037A
AS
3A
LDA
LINENO+1
670:
037C
48
PHA
680:
037D
A9
52
LDA
#"R"
;AND REPEAT CODE
690:
037F
48
PHA
;0N STACK
700:
0380
4C
AE
A7
JMP
INTER
; TO INTERPRETER
LOOP
710:
720:
0383
20
73
00
UNTIL
JSR
CHRGET
; CONDITION
FOLLOWS?
730:
0386
FO
D7
BEQ
SYNERR
;N0 THEN ERROR
740:
0388
20
8A
AD
JSR
FRMNUM
; EVALUATE CONDI-
TION
750:
038B
A8
TAY
;SAVE RESULT
760:
038C
BA
TSX
; STACK POINTER
TO X
770:
038D
BD
01
01
LDA
STACK+1,
X ; LAST STACK
154
Advanced Machine Language
780: 0390 C9 52 CMP
790: 0392 DO 23 BNE
800: 0394 98 TYA
810: 0395 DO 17 BNE
820:
830:
0397
BO
02
01
LDA
840:
039A
85
3A
STA
850:
039C
BD
03
01
LDA
860:
039F
85
39
STA
870:
03A1
BD
04
01
LDA
880:
03A4
85
7B
STA
890:
03A6
BD
05
01
LDA
900:
03A9
85
7A
STA
910:
03AB
4C
AE
A7
JMP
920:
1
930:
03AE
8A
RPTENDE TXA
940:
03AF
18
CLC
950:
03B0
69
05
ADC
960:
03B2
AA
TAX
970:
03B3
9A
TXS
980:
03B4
4C
AE
A7
JMP
990:
1
1000:
03B7
A9
CO
RPTEHR LDA
1010:
03B9
85
22
STA
1020:
03BB
A9
03
LDA
ENTRY
#"R" ;AND TEST FOR
REPEAT CODE
RPTERR ;N0, THEN ERROR
MESSAGE
RPTENDE ; EXPRESSION TRUE,
END LOOP
STACK+2,X
LINENO+1 ;6ET LINE NUMBER
STACK+3,X
LINENO
STACK+4,X
TXTPTH+1 ;AND PROGRAM
POINTER
STACK+5,X ;FROM STACK
TXTPTH
INTER ;T0 INTERPRETER
LOOP
; STACK POINTER
#5 ; INCREMENT BY 5
INTER ;AND TO INTER-
PRETER LOOP
#<TEXT
ADDR ;SET POINTER TO
ERROR MESSAGE
#>TEXT
155
Advanced Machine language
1030: 03BD 4C 45 A4 JMP ERROR
1040: ;
1050: 03C0 55 4E 54 TEXT .ASC "UNTIL WITHOUT REPEAT"
J033C-03D4
NO ERRORS
Now let's see how our new commands are used. For the
sake of simplicity we have designated our new commands with
a prefixed exclamation point "!" and an "R" for REPEAT and a
"U" for UNTIL. When you have the assembly language program
assembled and activated with SYS 828, you can try it out
with the following program:
100 1=0
110 !R
120 1=1+1 : PRINT I
130 !U 1=10
The program prints the numbers from 1 to 10. Nested loops
are also possible.
100 1=0
110 !R
120 1=1+1 : PRINT "I=" ! I : J=0
130 !R
140 J=J+1 : PRINT "J=" ; J
150 !U J=3
160 !U 1=3
In these nested loops the counter I runs from 1 to 3
and the counter J in the inner loop also from 1 to 3. The
above problem could be solved more simply with two nested
FOR-NEXT loops. The main applications area of the REPEAT
156
Advanced Machine LanguaKe
through the loop is not known when the loop started, but
will be determined during the loop. The stop criterium night
be a pressed key, for example. This program structure is
also very useful for iterations such as calculating a square
root using the Newton method.
100 INPUT "INPUT ";A
110 XI = A
120 !H
130 XO = XI
140 XI = (XO + A/X0)/2
150 !U ABS (Xl-XO) < lE-8
160 PRINT "THE ROOT IS " ; XI
Here an approximation is calculated until the differen-
ce between two successive values is less than 10^-8. Try
this with a few values and compare the result with that of
the SQR function.
Endless loops can also be constructed with this struct-
ure, by using an ending criterium which is never true. For
example
110 !R
110 PRINT TI
120 !U 1=0
This loop will never be exited by the program.
The REPEAT. .. UNTIL loop runs faster than an IF... GOTO
construction because the line number to which GOTO is dir-
ected must be searched for each time. With the UNTIL com-
mand, this address needs only to be fetched from the stack.
157
Advanced Machine Language
In addition, the progran is easier to read and understand
because the intentions of the prograniffler come through more
clearly.
We now cone to a description of the machine language
program. We proceed in much the same manner as the other
programs structures discussed earlier. After the usual init-
ialization in which the vector for command evaluation is
changed to point to our routine, we first test to see if a
new command was used. If no exclamation point was found,
control is returned to the original command evaluation rou-
tine. Otherwise the next character is fetched and checked to
see if it is "U" or "R". The routines REPEAT and UNTIL are
branched to accordingly. If neither of these two characters
were read, we jump to the error message "SYNTAX ERROR."
For the REPEAT command we set the program pointer to
the next character by a call to CHRGET and check to see that
enough space is left on the stack. We use the routine
NBXTSTAT to search for the next command, the relative ad-
dress of which we get back in the Y register. We add this
value to the program counter and place it on the stack. The
line number is also placed on the stack. To denote the data
set as a REPEAT command, we also push the letter "R" on the
stack. The data set in the stack is constructed according to
the 60SUB command. The work is now done and we return to the
interpreter loop.
The UNTIL command checks to see that a condition fol-
lows and evaluates it. The result Is saved in the Y regis-
ter. Now we load the X register with the stack pointer and
compare the top stack element with "R", the designator for
REPEAT. If this element was not an R, we output the message
158
I
Advanced Machine tanguaKe
"UNTIL WITHOUT REPEAT." Note that the last character of the
error message must be Shifted (bit 7 set). This is how the
error message output routine determines the end of the
message. If we did find an R, the next action is dependent
on the result of the condition. If the condition was not
met, we load the program pointer and line number from the
stack and jump to the interpreter loop. Note that the data
is not taken from the stack with PLA but with LDA STACK, X,
after the stack register was first copied into the X regis-
ter. This retains the value of the stack pointer and the
data remain for the next UNTIL command. If, however, the
condition was satisfied, we simply increment the stack
pointer by 5. This has the effect of removing the data set
from the stack and we continue with the next command.
159
Advanced Machine Language
3.4 Using new keywords
The easiest way to add new commands to the BASIC inter-
preter is to give the command a name by which you can access
it. Internally this keyword is stored in the form of a
token, an interpreter code which can range in value from $80
to $FF.
The Commodore 64 BASIC uses the tokens from $80 to $CB
for itself, as well as $f¥ for pi. If we want to add new
keywords, the interpreter codes from $CC (204) to $FE (254)
are available to us. We could therefore add up to 54 new
commands. Let us consider what is necessary in order to do
this.
First, there must be a routine which converts a line of
BASIC text into the new tokens upon input. The routine for
executing the commands must recognize the new token and call
the appropriate routine to execute this new command. So that
we can list our program, the LIST program must also be
changed to output the ASCII form of the new commands when it
finds the token. The most convenient way to do all this is
to place our new keywords and the addresses of the corres-
ponding routines in a table, exactly as the interpreter does
with the standard commands.
Recall from our discussion about BASIC vectors that
four vectors are necessary for these tasks. We have already
used the vectors for BASIC command execution ($308) and
function calculation ($30A). For converting keywords into
tokens we must use the vector $304. To convert tokens back
into keywords with the LIST command we must use the vector
$308.
160
Advanced Machine Language
Once we have written these routines, it is quite easy
to add new keywords. We need only place the keyword together
with the address of the routine which executes the command
In a table.
This procedure is also faster in execution because no
special characters such as "!" need be added for recognition
of the new command. In the program itself, the command
"REPEAT" looks better than "!R".
Before we venture to write a routine which converts new
keywords to tokens, we will first take a look at how the
BASIC interpreter handles this. In order to do this we have
re-assembled the ROM routine for you here. If we follow the
principle, it is not hard to change the routine to add our
own tokens.
100:
110:
120:
130:
140:
150:
160:
170:
180:
190:
200:
210:
220:
A57C
0083
008F
0099
0008
OOOB
0071
.OPT PI
ROM ROUTINE FOR CONVERSION TO TOKENS
SPECIAL TOKENS
DATA
REM
PRINT
>
CHAR
COUNT
PNT
$83
$8F
$99
8
11
$71
; ACTUAL CHARACTER
; COUNTER FOR COM-
MAND WORDS
; POINTER IN LINE
BEING CONVERTED FROM
161
Advanced Machine Language
230:
0022
QUOTE
$22
240:
OOOF
FLAG
15
;FLAG FOR DATA
AND REM
250:
007A
TXTPTH
$7A
POINTER IN LINE
BEING CONVERTED TO
260:
0200
BUFFER
_
$200
INPUT BUFFER
270:
280:
A09E
TABLE
=
$A09E
TABLE OF COMMAND
WORDS
290:
1
300:
A57C
*=
$A57C
ROM ROUTINE
310:
320:
A57C
A6
7A
LDX
TXTPTR
POINTER TO FIRST
CHARACTER
330:
A57E
AO
04
LDY
#4
POINTER TO LINE
CONVERTED FROM
340:
A580
84
OF
STY
FLAG
CLEAR FLAG
350:
A582
BO
00 02
NEXTCHAR
LDA
BUFFER. X
;GET CHARACTER
FROM BUFFER
360:
A586
10
07
BPL
NORMAL
370:
AS 87
C9
FF
CMP
*$FF
CODE FOR 'PI*
380:
A589
FO
3E
BEQ
TAKCHAR
;YES, TAKE IT
390:
A58B
E8
INX
OTHERWISE IGNORE
CHARACTER
400:
A58C
DO
F4
BNE
NEXTCHAR
410:
420:
A58E
C9
20
NORMAL
CMP
#" "
SPACE?
4ou :
A Ron
AO all
vn
O 1
TAKCHAR
;TAKE IT
440:
A5g2
85
08
STA
CHAR
SAVE CHARACTER
450:
A594
C9
22
CMP
#QU0TE
QUOTE?
460:
Asge
FO
56
BEQ
GETCHAR
; YES
470:
AS 98
24
OF
BIT
FLAG
TEST FLAG
480:
A59A
70
2D
BVS
TAKCHAR
;TAKE AS DATA
162
Advanced Machine Language
490: A59C C9 3F CMP
500: A59E DO 04 BNB
510: A5A0 A9 99 LOA
520: A5A2 DO 25 BNE
530: A5A4 C9 30 SKIP CMP
540: A5A6 90 04 BCC
550: A5A8 C9 3C CMP
560: A5AA 90 ID BCC
570: A5AC 84 71 SKIPl STY
580: A5AE AO 00 tDY
590: A5B0 84 OB STY
600: A5B2 88 DEY
810: A5B3 86 7A STX
620: A5B5 CA DEX
630: ;
640: A5B6 C8 CMPIOOP INY
650: A5B7 E8 INX
660: A5B8 BD 00 02 TESTNEXT LDA
670: A5BB 38 SEC
680: A5BC F9 9E AO SBC
690: A5BF FO F5 BBQ
700: A5C1 C9 80 CMP
710: A5C3 FO 30 BEQ
MODE
#"?•• ; QUESTION MARK
SKIP
*PRINT ; REPLACE WITH
PRINT CODE
TAKCHAR
#"0" ;LESS THAN '0'
SKIPl
#"<" ;LESS THAN '<'?
TAKCHAR ;YES, TAKE CHAR-
ACTER
PNT iSAVE POINTER IN
LINE
#0
COUNT ; COUNTER FOR COM-
MAND WORDS TO ZERO
TXTPTR ;SAVE LINE POINTER
; POINTER IN COM-
MAND TABLE
;AND INCREMENT
LINE POINTER
BUFFER, X ;GET CHARACTER
FROM BUFFER
TABLE, Y ; COMPARE WITH
COMMAND WORD
CMPLOOP ;SAME, THEN NEXT
CHARACTER
#$80 ;LAST LETTER?
NEXTCMD ; OTHERWISE POINT-
163
Advanced Machine Language
ER TO NEXT COMMAND
720:
A5C5
05
OB
ORA
COUNT ; FOUND #+$80=INTER
725:
A5C7
A4
71
TAKCHARl
LDY
PNT ;GET POINTER BACK
730:
t
740:
A5C9
E8
TAKCHAR
INX
750:
A5CA
C8
INY
760:
A5CB
99
FB
01
STA
BUFFER-5,Y ; SAVE CODE
770:
A5CE
B9
FB
01
LDA
BUFFER-5,Y ; RESTORE
FLAGS
780:
A5D1
FO
36
BEQ
END ;LINE END?
790:
A5D3
38
SEC
800:
A5D4
E9
3A
SBC
#":" ! SEPARATOR?
810:
A5D6
FO
04
BEQ
SKIP2 ; CLEAR DATA FLAG
820:
A5D8
C9
49
CMP
#DATA-":" ;CODE FOR
•DATA'
830:
A5DA
DO
02
BNE
SKIP3
840:
ASDC
85
OF
SKIP2
STA
FLAG ;SET BIT 6 FOR
'DATA'
850:
A5DE
38
SKIP3
SEC
860:
A5DF
E9
55
SBC
#REM-":" ;CODE FOR 'REM'
870:
A5E1
DO
9F
BNE
NEXTCHAR ;N0, GET NEXT
CHARACTER
880:
A5B3
85
08
STA
CHAR ;SAVB ZERO BYTE
FOR 'REM'
890:
A5E5
BD
00
02
REMLOOP
LDA
BUFFER, X
900:
A5E8
FO
DF
BEQ
TAKCHAR ;LINE END, TAKE
CHARACTER
910:
A5EA
C5
08
CMP
CHAR ;NBXT "" OR REM
. OR DATA
920:
A5EC
FO
DB
BEQ
TAKCHAR ;YES?
930:
A5EE
C8
GETCHAR
INV
940:
A5EF
99
FB
01
STA
BUFFER-5,Y ; TAKE CHAR-
ACTER
164
Advanced Machine Language
950:
A5F2
E8
INX
960:
A5F3
DO
FO
BNE
REMLOOP
970:
1
980:
A5F5
A6
7A
NEXTCND
LDX
TXTPTH ;
LINE POINTER TO
START OF WORD
990:
A5F7
E6
OB
INC
COUNT !
COUNTER TO NEXT
COMMAND WORD
1000
A5F9
C8
CONTINUE
INY
1010
A5FA
B9
9D
AO
IDA
TABLE-1,Y
1020
ASFD
10
FA
BPL
CONTINUE
;WORD NOT DONE!
1030
A5FF
B9
9E
AO
IDA
TABLE, Y
1040
A602
DO
B4
BNE
TESTNEXT
;TEST FOR NEXT
COMMAND WORD
1050
1
1060
A604
BD
00
02
IDA
BUFFER, X
1070
A607
10
BE
BPL
TAKCHARl
;TAKE CHARACTER
AS SUCH
1080
1090
A609
99
FC
01 END
STA
BUFFER-4,
Y ;END BUFFER
WITH ZERO
1100
1
1110
A60C
C6
7B
DEC
TXTPTR+1
1120
A60E
A9
FF
LDA
*$FF ;
TXTPTR TO $01FF,
BUFFEH-1
1130: A610
85
7A
STA
TXTPTH
1140
A612
60
RTS
] A57C-A613
NO ERRORS
When a line of BASIC text is to be converted to tokens.
It must be placed into the BASIC input buffer located at
$200 to $258. The pointer TXTPTR ($7A/$7B) must point to the
first character following the line number. The X register is
165
Advanced Machine Language
loaded with this pointer. The X register serves throughout
the entire routine as a pointer to the text to be converted.
The Y register is used as a pointer^ in the converted line.
After the FLAG is cleared, the first character of the line
is examined. If the ASCII value of this character is greater
than $7F, it is checked for the code 255 for pi. If this
test was positive, the character is accepted as such. All
other characters with bit 7 set are ignored; the pointer is
incremented and the next character is tested. If the char-
acter is a normal unshifted character, it is checked for a
special character. A space is accepted unchanged. Otherwise
the current character is saved in CHAR. If the character is
a quotation mark ("), a branch is made to GETCHAR where
characters are read until another quotation mark is encount-
ered. A DATA statement is recognized by checking FLAG. If a
DATA command is active, text is accepted unchanged. The code
is next replaced with "PRINT". After the digits and the
characters ";" and ":" are filtered out and accepted un-
changed, cones the actual conversion to tokens.
The pointer in the line being converted (X register) is
stored in PNT and the counter for the token number of the
keyword is initialized. The comparison is executed at the
label CMPLOOP. The current character in the buffer is com-
pared to the first letter in the keyword table. If the
characters are equal, the next character is compared to the
second letter. If these are equal, the difference is checked
to see if it is $80. This value denotes the character as the
last character of a command in the keyword table because it
is stored with bit 7 set. If this is true, the accumulator
contains the difference $80. By logical ORing with the
command number COUNT you get the token number, which is then
saved. If the characters were not equal, however, the start
166
Advanced Machine Language
of the next keyword is found by NEXTCMD and the counter for
the number of keywords is incremented by one. If we are not
at the end of the table, a branch is made back to the
compare loop where the next word from the table is compared.
If the end of the table was found (denoted by a zero byte),
the current character is accepted unchanged.
After either the token or the unchanged character is
stored by the routine at label TAKCHAR, the special char-
acters are handled. If the colon is found, FLAG is cleared
so that it can be be set again by another DATA statement. If
the REM command was found, the current character is saved as
a zero and all of the characters up to a zero (end of line)
are accepted unchanged by RBMtOOP. At the end of the rou-
tine (label BND), the converted buffer is terminated with a
zero and TXTPTH set to one character before the buffer.
If we now want to convert our own keywords to tokens,
we must ensure that the table containing our own commands is
searched after the command table in ROM. In addition we must
determine which tokens we want to use for the new keywords.
The tokens starting at $CC should be used since they follow
the existing commands directly.
100:
COOO
.OPT PI
110:
120:
; ROUTINE
FOR USING
130:
140:
; SPECIAL
TOKENS
150:
160:
0083
DATA
$83
170:
008F
REM
$8F
180:
0099
PRINT
$99
167
Advanced Machine Language
190:
200:
210:
220:
230:
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
360:
370:
380:
390:
400:
410:
420:
430:
440:
0008
OOOB
0071
0022
OOOP
007A
0200
A09E
COOO
GOOD A6 7A
C002 AO 04
C004 84 OF
CHAR
COUNT
PNT
QUOTE
FLAG
TXTPTH
BUFFER
i
TABLE
LDX
LDY
STY
COOS BD 00 02 NEXTCHAR LDA
COOS 10 07
COOB C9 FF
COOD FO 3E
COOF E8
COlO DO F4
C012 C9 20
C014 FO 37
C016 85 08
BPL
CMP
BEQ
INX
BNE
NORMAL CMP
BEQ
STA
8
11
$71
$22
15
$7A
$200
$A09E
; INPUT BUFFER
; TABLE OF COMMAND
WORDS
$C000 ;NEW ROUTINE
TXTPTR i POINTER TO FIRST
CHARACTER
#4 ; POINTER WITHIN
LINE BEING CONVERTED
FLAG ;FLAG FOR SPECIAL
CHARACTERS
BUFFER, X ;GET CHARACTER
FROM BUFFER
NORMAL
#$FF ;C0DE FOR 'PI'?
TAKCHAR iYES, TAKE CODE
AS SUCH
; OTHERWISE IGNORE
CHARACTER
NEXTCHAR
#" " ; SPACE?
TAKCHAR ;TAKE AS SUCH
CHAR iSAVE CHARACTER
168
Advanced Machine Language
450: C018 C9 22
460: COIA FO 55
470: COIC 24 OF
480: COIE 70 2D
490: C020 C9 3F
500: C022 DO 04
510: C024 A9 99
520: C026 DO 25
530: C028 C9 30
540: C02A 90 04
550: C02C C9 3C
560: C02E 90 ID
570: C030 84 71
580: C032 AO 00
590: C034 84 OB
600: C036 88
610: C037 86 7A
620: 0039 CA
630:
640: C03A C8
650: C03B E8
660: C03C BD 00
670: C03F 38
680: C040 F9 9E
690: C043 FO F5
700: C045 C9 80
CMP
BEQ
BIT
BVS
CMP
BNE
LDA
BNE
SKIP CMP
BCC
CMP
BCC
SKIP! STY
LDY
STY
DEY
STX
DEX
>
CMPLOOP INY
INX
02 TESTNBXT LDA
SEC
AO SBC
BEQ
CMP
♦QUOTE ; QUOTE?
6ETCHAR
FLAO ;DATA MODE?
TAKCHAH JYES, TAKE AS
SUCH
#"?" ; QUESTION MARK?
SKIP
*PRINT ; REPLACE WITH
PRINT CODE
TAKCHAR
#"0" ; SMALLER THAN '0'?
SKIPl
#"<" ;LESS THAN '<'?
TAKCHAR I YES, TAKE CHAR-
ACTER AS SUCH
PNT ;SAVE LINE POINTER
*0
COUNT ; COUNTER FOR COM-
MAND WORDS TO
TXTPTH
; INCREMENT POINTER
BUFFER, X ;GBT CHARACTER
FROM BUFFER
TABLE, Y ; COMPARE WITH
COMMAND WORDS
CMPLOOP ;SAME, THEN NEXT
CHARACTER
#$80 ;LAST LETTER?
169
Advanced Machine Language
710: C047 DO 2F
720: C049 05 OB
730: C04B A4 71 TAKCHARl
740: ;
750: C04D E8 TAKCHAR
760: C04B C8
770: C04F 99 FB 01
780: C052 C9 00
790: C054 FO 38
800: C056 38
810: C057 E9 3A
820: C059 FO 04
830: C05B C9 49
840: COSD DO 02
850: C05F 85 OF SKIP2
860: C061 38 SKIPS
870: C062 E9 55
880: C064 DO AO
890: C066 85 08
900: C068 BD 00 02 REMLOOP
910: C06B FO EO
920: C06D C5 08
930: C06F FO DC
940: C071 C8 GETCHAR
950: C072 99 FB 01
BNE NEXTCHD ; OTHERWISE POINT-
ER TO NEXT COMMAND
ORA COUNT !#+$80 = INTER-
PRETER CODE
LDY PNT ;GET POINTER BACK
INX
I NY
STA BUFFER-5,Y ; SAVE CODE
CMP *0 ;6ET FLAGS BACK
RBO END ;END OF LINE?
SEC
SBC #":" ; SEPARATOR?
BEQ SKIP2
CMP tDATA-":" ;CODE FOR
•DATA*?
BNE SKIP3
STA FLAG ;SET BIT 6 FOR
'DATA'
SEC
SBC #REM-":" ; CODE FOR 'REM'?
BNE NEXTCHAR ;N0, GET NEXT
CHARACTER
STA CHAR ;SAVE CHARACTER
LDA BUFFER, X
BEQ TAKCHAR ; END OF LINE,
TAKE AS SUCH
CMP CHAR ;NEXT 'N' OR REM
OR DATA
BEQ TAKCHAR ; YES
INY
STA BUFFER-5,Y ; TAKE CHAR-
ACTER
170
Advanced Machine Language
960: COTS E8
970: C076 DO FO
980: ;
990: C078 A6 7A fJEXTCMD
1000: C07A E6 OB
1010: C07C C8 CONTINUK
1020: C07D B9 9D AO
1030: C080 10 FA
1040: C082 B9 9E AO
1050: C08S DO B5
1060: C087 FO OF
1070: ;
1080: C089 BD 00 02 NOTFOUND
1090: C08C 10 BD
1100: ;
1110: COSE 99 FD 01 END
1120: !
1130: C091 C6 7B
1140: C093 A9 FF
1150: C095 85 7A
1160: C097 60
1170: ;
1180: iWORK ON
1190: C098 AO 00 NEWTOK
1200: C09A B9 C3 CO
1210: C09D DO 02
INX
BNE REMLOOP
LDX TXTPTH
INC COUNT ; POINTER TO NEXT
COMMAND WORD
INY
IDA TABLE-l.Y ; NEXT LETTER
BPL CONTINUE ; WORD NOT DONE?
IDA TABLE, Y
BNE TESTNEXT ;TEST FOR NEXT
COMMAND WORD
BEQ NEWTOK i USB NEW TABLE
LDA BUFFER, X
BPL TAKCHAHl ; TAKE CHR AS
SUCH
STA BUFFER-3,Y i LINK BYTE
ZERO FOR DIRECT NODE
DEC TXTPTR+1
LDA #$FF ;TXTPTR TO $01FF,
BHFFER-1
STA TXTPTR
RTS
NEW COMMAND
LDY #0 ; POINTER TO START
OF NEW TABLE
LDA NEWTAB,Y ; GET FIRST CHAR-
ACTER FROM TABLE
BNE NEWTEST
171
Advanced Machine Language
1220: ;
1230: C09F C8 NEWCNP INY
1240: COAO E8 INX
1250: COAl BD 00 02 NEWTEST LDA
1260: C0A4 38 SEC
1270: C0A5 F9 C3 CO SBC
1280: C0A8 FO F5 BEQ
1290: COAA C9 80 CMP
1300: COAC DO 04 BNE
1310: COAE 05 OB ORA
1320: COBO DO 99 BNE
1330: ;
1340: C0B2 A6 7A NEXTNEW LDX
1350: C0B4 E6 OB INC
1360: C0B6 C8 CONTl INY
1370: C0B7 B9 C2 CO LDA
1380: COBA 10 FA BPL
1390: COBC B9 C3 CO LDA
1400: COBF DO BO BNE
1410: COCl FO C6 BEQ
1420: ;
1430: C0C3 52 45 50 NEWTAB .ASC
1440: C0C9 55 4E 54 .ASC
1450: COCE 43 4F 4D .ASC
1460: C0D5 00 .BYT
]C000-C0D6
BUFFER, X ; COMPARE ROUTINE
FOR NEW
; COMMAND TABLE
NEWTAB, Y
NEWCMP
#$80
NEXTNEW ;TEST FOR NEXT
COMMAND
COUNT ; FOUND
TAKCHARl ; ABSOLUTE JUMP
TXTPTR
COUNT ; INCREMENT TOKEN
NUMBER
NEWTAB-1,Y ; POINTER TO
NEXT COMMAND WORD
CONTl
NEWTAB, Y
NEWTEST [COMPARE TO
INPUT LINE
NOTFOUND ;BND OF NEW
TABLE
"REPEAT" ; TABLE OF
NEW COMMAND WORDS
"UNTIL"
"COMMAND"
;END OF TABLE
172
Advanced Machine Language
NO ERRORS
With these routines we can convert our own keywords to
tokens. When entering the new keywords in the new table you
must be sure that the last character of each coamand is
entered with bit 7 set. This is done by pressing shift when
the entering the character. In our assembly listing this is
represented as an underlined character. The new commands can
also be abbreviated as desired. reP could be used for repeat
or uN for until.
With our procedure you can assign the new keywords a
token value from $CC to $FE. This gives us a maximum of 51
new command words. Because this table is indexed with an 8-
bit register, the total length of the commands may not be
longer than 255 characters. The end of the table must be
denoted by a zero byte.
In order to activate our new routine we must set the
vector $304/$305 to the routine. Before we do this, we first
want to write a routine which allows us to LIST the new
keywords. The BASIC vector $306/$307 is used for this.
Converting tokens to ASCII text takes place here; the organ-
izational work such as taking care of the line end and line
numbers is handled by the list routine. Let us take a look
at the interpreter LIST routine.
173
Advanced Machine language
100:
110:
120:
130:
140:
150:
160:
170:
180:
190:
200:
210:
220:
-30:
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
A71A
OOOF
0049
A09E
AB47
A71A
A71A 10 D7
A71C C9 FF
A71E FO D3
A720 24 OF
A722 30 CF
A724 38
A725 B9 7F
A727 AA
A728 84 49
A72A AO FF
A72C CA
A72D FO 08
A72F C8
A730 B9 9E AO
A733 10 FA
A735 30 F5
.OPT PI
INTEHPRETBR LIST ROUTINE
QU0TFL6 =
PNT
TABLE
CHAROUT =
NEXT
LOOP
* =
BPL
CMP
BEQ
BIT
BMI
SBC
SBC
TAX
STY
LDY
DEX
BEQ
INY
LDA
BPL
BMI
15
$49
$A09E
$AB47
$A71A
$A6F3
#$FF
$A6F3
QU0TFL6
$A6F3
*$7F
PNT
#-1
; FLAG FOR QUOTE
NODE
; INTERPRETER COM-
MAND TABLE
I OUTPUT CHARACTER
;N0 INTERPRETER
CODE, SO OUTPUT
;CODE FOR PI,
OUTPUT
; QUOTE MODE?
;YES, OUTPUT
UNCHANGED
iSUBRACT OFFSET
iSAVE CODE AS
COUNTER
;SAVE POINTER
FOUND ;XTH COMMAND WORD
FOUND?
TABLE, Y
LOOP ;WOHD NOT DONE?
NEXT ;NEXT WORD
174
Advanced Nachine Language
360:
370:
380:
390:
400:
410:
A737 C8 FOUND
A738 B9 9E AO
A73B 30 B2
A73D 20 47 AB
A740 DO F5
INY
LDA TABLE, Y i GET LETTER
BMI $A6EF ;LAST CHAHACTBR?
JSR CHAROUT ; OUTPUT CHARACTER
BNE FOUND ; ABSOLUTE JUMP
]A71A-A742
NO ERRORS
The routine checks for interpreter codes (is bit 7
set?). The special code for pi is left unchanged. This is
also ignored in the quote mode. First we search for the
keyword. The token is brought into the range 1-76 by sub-
tracting $7F. Then the keyword table is searched and the
token number is decremented by one at the end of each key-
word, which is denoted by the set bit 7. When the number
counts down to zero, we have found the appropriate word in
the table. Now we output all characters until we encounter
the one with bit 7 set. In this case we branch back to the
list routine. There bit 7 is cleared as the character is
printed.
If we have new tokens to list, we need only check to
see if the token is greater than $CB. If this is the case,
we can search for the keyword in our new table using the
same method, otherwise we leave the work for the original
routine.
100:
110:
120:
130:
140:
COOO
OOOF
.OPT PI
LIST ROUTINE FOR NEW COMMANDS
QUOTFLG
15
175
Advanced Machine Language
150:
160:
170:
180:
190:
410
420
430
440
450
0049
A09E
AB47
COOO 10 OF
PNT = $49
TABLE = $A09E ; COMMAND TABLE
CHAHOUT = $AB47 ; OUTPUT CHARACTER
BPL OUT
200:
C002
24
V r
210:
C004
30
OB
220:
C006
C9
FF
230:
C008
FO
07
240:
COCA
C9
CC
250:
COOC
BO
06
260:
270:
COOE
4C
24
A7
280:
coil
4C
F3
A6
290:
300:
C014
38
310:
COIS
Eg
CB
320:
0017
AA
330:
C018
84
49
340:
COIA
AO
FF
350:
COIC
CA
360:
COID
FO
08
370:
COIF
C8
380:
C020
B9
35
CO
390:
C023
10
FA
400:
C025
30
F5
NEWLIST
NEXT
LOOP
C027 C8 FOUND
C028 B9 35 CO
C02B 30 06
C02D 20 47 AB
BIT
BMI
CMP
BEQ
CMP
BCS
JMP
JMP
SEC
SBC
TAX
STY
LDY
DEX
BEQ
I NY
LDA
BPL
BMI
INY
LDA
BMI
JSR
QUOTFLG
OUT
#$FF
OUT
#$cc
NEWLIST
;N0 TOKEN, SO
OUTPUT
; QUOTE MODE?
;S0 OUTPUT
;PI?
;S0 OUTPUT
;NEH TOKEN?
;YES
$A724 ;LIST OLD TOKENS
$A6F3 ; OUTPUT BYTE
#$CB
PNT
#-1
FOUND
; SUBTRACT OFFSET
iCODE AS COUNTER
;WOHD FOUND?
; YES
NEWTAB, Y
LOOP ; EXPECT END OF
WORD
NEXT ;NBXT WORD
NEWTAB, Y ; COMMAND WORD
OLDEND ;AT END?
CHAROUT ; OUTPUT CHARACTER
176
Advanced Machine Lantfuafe
460: C030 DO F5 BNE FOUND ; AND CONTINUE
470:
480: C032 4C EF A6 OLDEND JMP $A6EF ; TO OlD ROUTINE
490: ;
500: C035 52 45 50 NEWTAB .ASC "REPEAT" ; COMMAND
TABLE
510: C03B 55 4E 54 -ASC "UNTIL"
520: C040 43 4F 4D -ASC "COMMAND"
530: C047 00 -BYT
]C000-C048
NO ERRORS
When we change the LIST vector $306-$307 to point to
this routine, we can list our new commands correctly. The
keyword table NEWTAB is naturally identical to the table in
the routine for creating new tokens and can be shared. In a
practical application you should assemble the two routines
together and create a single initialization program which
changes both vectors appropriately.
We need routines which allow us to process the new
commands from the BASIC interpreter which can call the new
commands and functions. This happens, as we know, by using
the vector $308/$309 for commands and $30A/$30B for func-
tions. To simplify the processing, the new commands should
be assigned tokens such that they form a block. The routines
can then verify that the token lies in the range of new
commands or functions. The token value can be used as a
pointer to a table which contains the starting addresses of
the routines which perform the new commands. This is the
same procedure which the built-in interpreter uses. We now
present a universal routine which handles the processing of
new tokens. You need only establish the range of the new
177
Advanced Machine Language
coBoands and functions and place the starting addresses of
the corresponding routines in the table.
100:
110:
120:
130:
140:
150:
160:
170:
180:
190:
200:
210:
215:
217:
218:
219:
220:
300:
310:
320:
330:
COOO
0308
030A
OOOD
0073
0079
007A
A7ED
A7AE
AE8D
AEFl
AD8D
0054
OOCC
OOEO
OOEl
,OPT PI
INCLUDING NEW TOKENS
CMDVBC
FUNVEC
TYPFLAG =
CHRGET
CHRGOT
TXTPTR
EXECOLO =
INTER
FONCTOLD =
GETTERM =
CHECKNUM =
JUMP
CMDSTART =
CMDEND
t
FUNSTART =
$308
$30A
13
; COMMAND VECTOR
; FUNCTION VECTOR
;FLAG NUMERIC/
STRING
$73
CHRGET-t^e
CHRGOT+1
$A7ED ;OLD COMMAND
EXECUTION
$A7AE ; INTERPRETER LOOP
$AE8D ;OLD FUNCTION
CALCULATION
$AEF1 ;6ET EXPRESSION
IN PARENTHESES
$AD8D ; TEST FOR NUM-
ERICAL RESULT
$54 iJUMP COMMAND FOR
FUNCTIONS
$CC ; FIRST COMMAND
TOKEN
$E0 ; LAST COMMAND
TOKEN
$E1
i FIRST FUNCTION
178
Advanced Machine Lan<ua«e
340: OOFE FUNEND
350: ;
400: COOO A9 15 INIT
410: C002 AO CO
420: C004 8D 08 03
430: C007 8C 09 03
440: ;
450: COOA A9 3C
460: COOC AO CO
470: COOE 8D OA 03
480: coil 8C OB 03
490: C014 80
500: ;
510: C015 20 73 00 NEWCMD
520: C018 20 IB CO
530: COIB 4C AE A7
550: COIE C9 CC TBSTCMD
580: C020 90 04
570: C022 C9 El
580: C024 90 06
590: C026 20 79 00 OLDCMD
600: C029 40 ED A7
610: ;
620: C02C 38 OKNEW
630: C02D B9 CC
640: C02F OA
650: C030 AA
660: C031 BD 6F CO
TOKEN
$FE ;LAST FUNCTION
TOKEN
IDA *<NEWCMD
LDY *>NEWCMD
STA CMDVEC ; COMMAND VECTOR
STY CMDVEC+1
LDA *<NEWFUN
LDY #>NEWFUN
STA FUNVEC ; FUNCTION VECTOR
STY FUNVEC+1
RTS
JSR CHRGET ; NOT TAKEN
JSR TBSTCMD j EXECUTE COMMAND
JMP INTER ;BACK TO INTER-
PRETER LOOP
CMP #CMDSTART
BCC OLDCMD ; OLD COMMAND?
CMP #CMDEND+1
BCC OKNEW ; EXECUTE NEW
COMMAND
JSR CHRGOT ; REPLACE FLAGS
JMP EXBCOLD ;AND EXECUTE OLD
COMMAND
SEC ; NEW COMMANDS
SBC tCMDSTAHT ; SUBRACT OFFSET
ASL ; TIMES 2
TAX
LDA CMDTAB+l.X ; HIGH BYTE
179
Advanced Machine Language
670:
C034 48
rnA
; RETURN ADDRESS
ON STACK
680 :
C035 BD 6E CO
LDA
CMDTAB, X
CUoo 48
PHA
;LOW BYTE
700:
f*(\*iO An TO nn
JMP
CHRGET J GET NEXT
CHARACTER
7 1 n •
1 1 u •
1
720:
UUO^y Ail UU
NEWFUN
LDA
#0
730:
fifl'^R His An
STA
TYPFLAG jTYPE TO NUMERIC
740:
Cii\il(\ 9n AA
vu*rU £U CO UU
JSR
CHRGET ;GET TOKEN
750:
C043 CQ Rl
CMP
#FUNSTART
760:
C045 90 04
BCC
viiUBun , ULU rUHCTION?
770:
CMP
#FUNEND+1
taU :
C049 90 06
BCC
OKINEH
790:
C04B 20 7Q nn
A T n crru
ULU frVN
JSR
CHHGOT ; REPLACE FLAGS
800:
C04E 4C 8D AE
JMP
ruNi/iULli ; CALCULATE OLD
FUNCTION
Q1 n •
1
820:
C051 38
OKINEW
SEC
; NEW FUNCTION
830:
SBC
#FUNSTART ; SUBTRACT
OFFSET
840:
C054 OA
ASL
850:
C055 48
PHA
1 oAVE POINTER TO
TABLE
oou i
C056 20 73 00
JSR
CHRGET ;GET NEXT
CHARACTEH
870:
C059 20 F1 AR
JSR
GETTERM ;GET FUNCTION
ARGUMENT
880:
C05C 68
P T A
r L A
890:
C05D AA
TAX
; POINTER AS INDEX
900:
C05E B9 72 CO
LDA
FUNTAB.y ;L0W ADDRESS
910:
C061 85 55
STA
JUMP+1
920:
C063 89 73 CO
LDA
FUNTAB+1,Y ;HIGH ADDRESS
180
Advanced Machine Language
930:
940:
950:
960:
970:
980:
990:
1000:
1010:
1020:
]C000
C066 85 56
C068 20 54 00
C06B 4C 8D AD
STA JUMP+2
JSH JUMP ; EXECUTE FUNCTION
JMP CHECKNUM ; TEST RESULT
FOR NUMERIC
COSE
C06E
C06E
C06E
-C06E
CMDTAB .WOH CMDl-1 ; TABLE OF COMMAND
ADDRESSES -1
.WOR CMD2-1
I • • • •
FUNTAB .WOR FUNl ; TABLE OF FUNCTION
ADDRESSES
.WOR FUN2
If you want to use this routine, you need only place
the numbers of the first and last new tokens in lines 300
and 310 and the corresponding numbers for numerical func-
tions in lines 330 and 340. A table is placed at lines 950
on so that the routine knows where the new commands are
located. This table contains the address of the routines
which execute the commands. Because the routines are called
with RTS by first placing the return address on the stack,
one is subtracted from the addresses because the return
address is automatically incremented by one by the RTS
command. This is not necessary for functions which are
called using the normal JSR call.
181
Advanced Machine Language
3.5 Operating sjrstea vectors
We shall review the important functions which use oper-
ating system jump vectors that can be changed. In addition
to the hardware vectors IRQ, BRK, and NMI which we have
already looked at, we will discuss all of the elementary
input/output functions which use these vectors. These func-
tions are addressed over the kernel routines at $FXXX. The
following table contains a list of these vectors and the
addresses to which these vectors point after power-up.
Vector
Address
Significance
$0314/$0315
$EA31
IRQ vector
$0316/$0317
$FE66
BRK vector
$0318/$0319
$FE47
NMI vector
$031A/$03IB
$F34A
OPEN vector
$031C/$031D
$F291
CLOSE vector
$031E/$031F
$F20E
CHKIN vector
$0320/$0321
$F250
CKOUT vector
$0322/$0323
$F333
CLRCH vector
$0324/$0325
$F157
BASIN vector
$0326/$0327
$F1CA
BSOUT vector
$0328/$0329
$F8ED
STOP vector
$032A/$032B
$F13E
GET vector
$032C/$032D
$FE66
warnstart vector (unused)
$032E/$032F
$F4A5
LOAD vector
$0330/$0331
$F5ED
SAVE vector
We will become acquainted with the significance of the
vectors and the functions of the routines to which they
pertain. With this knowledge we can then write our own
input/output functions.
182
Advanced Machine Language
OPEN - JSR $FFCO
This routine performa the same task as the BASIC co»-
mand by the same name. The parameters used by the equivalent
BASIC command must be taken care of before the routine is
called. There are two other routines which are used to do
this .
SETFLS - JSR $FFBA
This routine sets the parameters for the logical file
number, device number, and secondary address. The parameters
are passed in the processor registers:
LDA IF i logical file number
LDX DN ; device number
LDY SA ; secondary address
JSR SETFLS ; set parameters
The routine SBTNAM - JSR $FFBD exists for passing the file-
name. You must provide the length as well as the address of
the filename. If no filename is used, the length is given as
zero.
LDA #NAME1-NAME ; length of the name
LDX #<NAME ; low byte of the address
LDY #>NAME ; high byte of the address
JSR SETNAM ; pass parameters
NAME .ASC "FILENAME"
NAMEl = * ; end of the name
183
Advanced Machine Language
Once these two routines have done their work, the OPEN
routine can be called.
JSR OPEN
This opens the logical file. The following procedure permits
one to recognize any errors which may occur. The carry flag
is used as an error flag. If the flag is cleared after the
routine call, the routine was executed without error. If an
error did occur, however, the carry flag will be set and the
accumulator will contain the error number. These error num-
bers have the following meanings:
No.
Meanintf
halt via STOP key
1
too many files
2
file open
3
file not open
4
file not found
5
device not present
6
not input file
7
not output file
8
missing filename
9
illegal device number
240
RS 232 open/close
The carry flag should be tested after a kernal routine call
in order to check the error status.
JSR OPEN ; open file
BCC OK J everything OK?
JMP ERROR
OK
184
Advanced Machine Language
The error numbers correspond to the error messages
which we are already acquainted with from BASIC. A new error
number occurs upon OPEN or CLOSE with device number 2, the
HS 232 interface. As you may know, two 256-byte buffers are
allocated when an RS 232 channel is opened. These buffers
are placed at the top end of the BASIC area. This normally
results in the end-of-BASIC being moved from $A000 to $9E00.
Since strings are normally placed in this area, this area is
no longer available. In order to inform the BASIC inter-
preter of this situation, the error flag is set and the
error number 240 is passed. Upon receipt of this error, the
interpreter executes a CLR command, thereby clearing all of
the variables. These buffers are freed upon CLOSEing the
channel and the variables are again cleared. If you use the
HS-232 interface in your BASIC programs, the OPEN command
should be one of the first statements in the program and the
CLOSE command should be executed last. This ensures that no
variables will be lost during the course of the program.
As an alternative, you could also change the OPEN
routine. You could simply place the buffers in the area
beginning at $C000 when opening the HS-232 interface. This
has no effect on the BASIC program area and the CLR command
can be dispensed with.
The carry flag is also used as an error flag for the
I/O routines that will be discussed shortly and the accumu-
lator also contains the error number.
The operating system even has its own routine for
outputting error messages. The output appears in the form
I/O ERROR #X
185
Advanced Machine Language
in which X is the error number (1 to 9). The program is not
stopped when an error is encountered. We can activate the
error output by calling the routine SETNSG - JSR $FF90 with
a value of $40 in the accumulator (bit 6 set). The error
messages can be turned off by calling SETMSG with a value of
zero in the accumulator.
An additional function of the routine SETMSG is to
distinguish between program mode and the direct mode. Bit 7
is used for this. If bit 7 is cleared, the program mode is
designated and status messages of the operating system such
as "SEARCHING FOR", "LOADING", and "SAVING" are suppressed.
CLOSE - JSR $FFC3
The CLOSE routine requires only one parameter: the
logical file number, passed in the accumulator.
LDA LF
JSR CLOSE
Ko error messages can occur when using the CLOSE command. An
exception to this is the closing of an RS-232 channel. Here
'The buffer is freed and the BASIC interpreter executes a CLR
command. An attempt to close an unopened file does not
result in an error message.
CHKIN - JSR $FFC6
This command serves to redirect the input from the
keyboard to an opened file. If you want to read data from
the diskette, you must first open the file and then use this
186
Advanced Machine Language
file as input with CHKIN. The logical file number must be in
the X register for the call.
LDX LF
JSR CHKIN
Here too, errors are recognized through the set carry flag.
If the file was not previously opened, we get "FILE NOT
OPEN"; if you try to read a cassette file, a "NOT INPUT
FILE" error results. The actual input is performed by. the
routine BASIN, introduced later.
CKOUT - JSR $FFC9
The routine CKOUT is to output what CHKIN is to input.
It allows the output to be redirected to a previously opened
file. The CKOUT routine corresponds to the BASIC command
CMD. The logical file number is again passed in the X regis-
ter.
LDX LF
JSR CKOUT
The possible errors correspond to those for CHKIN. An at-
tempt to write to a tape file results in "NOT OUTPUT FILE."
The output is performed with BSOUT.
BASIN - JSR $FFCF
This routine can be compared to the INPUT command in
BASIC. If you have not redirected the input with CHKIN, you
can get characters from the keyboard or from the screen. If
you call BASIN from within a machine language program, the
187
Advanced Machine Language
cursor appears on the screen and you can enter characters
until you press RETURN. BASIN returns, in the accumulator,
the first character entered. Bach additional call of BASIN
gets an additional character until RETURN (CHR$(13)) is
encountered. This allows you to make full use of the screen
editor. If, however, you want characters from an opened
file, corresponding to the INPUT* command, you must first
call CHKIN which redirects input from this file. The BASIN
routine then gets a character from this file upon each call
and returns this character in the accumulator.
BSOUT - JSR $FFD2
We can output characters with the BSOUT routine. The
character in the accumulator will be printed on the screen.
For example:
LDA #$41
JSR BSOUT
This prints the character with the ASCII value $41 or 65
(the letter A) on the screen. You can also output control
characters or color codes, exactly as with the BASIC command
PRINT CHR$(X);. A new-line, as is possible in BASIC with a
PRINT command without a terminating semicolon, must be ex-
plicitly specified in machine language.
LDA #13 ; carriage return
JSR BSOUT ; output
If you do not want to output the characters on the screen,
but rather to the printer or to a disk file, you must first
open the appropriate file and use the routine CKOUT. This
188
Advanced Machine Languatfe
routes the output to the file and all calls of BSOUT output
the character not to the screen, but to that file. Error
messages such as "DEVICE NOT PRESENT" may occur if the
device on the serial bus does not answer.
CLRCH - JSR (FFCC
The routine CLRCH has the opposite function as CHKIN
and CKOUT. While these routines redirect input or output to
a logical file, CiRCH resets the standard I/O devices — the
keyboard and the screen. If you want to get 10 characters
from logical file 2 from the disk, the appropriate program
fragment
looks
like this:
LDX
#2 ;
logical file number
JSR
CHKIN
; input from file #2
LDY
#0
LOOP JSR
BASIN
; get character from the
STA
STORE
, Y ; and store
INY
CPY
#10 ;
10 characters?
BNE
LOOP
; no
JSR
CLRCH
; back to standard input
The logical file 2 must be opened before using this
fragment. The input is routed from the file with CHKIN, ten
characters are read with BASIN and stored, and the standard
input is re-established from the keyboard with CLRCH. The
file remains open; closing must be done explicitly with
CLOSE.
GET - JSR $FFE4
189
Advanced Machine Language
This routine corresponds to the GET routine of BASIC.
You can get a character from the keyboard with it. If no key
is pressed at the tine the routine is called, a zero is
returned, exactly as in BASIC where a null string is return-
ed if no key is pressed. A loop to wait for a keypress is
constructed as follows:
LOOP JSR GET
BEQ LOOP
The loop waits until a key is pressed. The GET command
can also be used on a logical file. As with BASIN, the
logical file must first be set with CHKIN. The GET command
on a file works the same way as the BASIN routine. After a
GET on a logical file a call to CLRCH is necessary in order
to reactivate the standard input.
CLALL - JSR $FFE7
This routine performs the sane tasks as CLRCH. In
addition, however, the number of open files is set to zero.
This has the effect of closing all of the files. The corres-
ponding CLOSE routine is not called. A file opened for
writing on the disk is not closed properly. This routine is
called by the BASIC interpreter for each RUN command.
LOAD - JSR $FFD5
This is the operating system LOAD routine. Before call-
ing this routine, the device number, secondary address, and
filename must be set. This can be done with the routines
SETFLS and SETNAM which were discussed in connection with
the OPEN command. A program can be loaded at the address
190
Advanced Machine Langu«<e
from which it was saved and which is stored in the disk or
datasette file, or it can/ be. loaded at an address passed to
the LOAD comnandt depending on the secondary address. With a
secondary address of zero, the file (progran) is loaded at
the address passed in the X (LSB) and Y (MSB) registers. The
contents of the accumulator determines if a load or a verify
is to be executed.
IDA #0 ; flag for LOAD
LDX #<ADDRESS ; start address
LDY #>ADDRESS
JSH LOAD
STX ENDADDR ; end address LSB
STY BNDADDR-M ; MSB :
For the case in which the secondary address is zero,
the program is loaded at the address given by ADDRESS. The
ending address of the loaded program is returned in the ,. X
and Y registers. If the program is not to be loaded but only
compared with the program in memory (verified), a 1 must be
passed in the accumulator.
LDA #1 ; flag for VERIFY
JSR LOAD
If the secondary address is one, the file is loaded at
the address specified within the file itself and we need not
pass the start address in X and Y. For VERIFY, a verify
failure is denoted by a status value (STATUS is located at
address $90) other than zero. Bit 6 (value 64) must be
masked out since this signals. the end of the program.
191
Advanced Machine Language
LDA STATUS
AND #X10111111 ; mask EOF BIT
BEQ OK
JMP ERROR
SAVE - JSR $FFD8
With the SAVE routine it is possible to save a section
of memory to a peripheral device. The device number and the
filename must again be previously specified with SETFLS and
SETNAM. The routine itself must be given the starting ad-
dress and ending address-«-l of the area to be saved. The
ending address plus one must be contained in the X and Y
registers. The accumulator must contain a pointer- to the
zero page address at which the low and high bytes of the
starting address are stored. If for example we want. to save
the area from $1234 to $1FFF, the call looks like this:
LDA #<$1234
STA START
LDA #>$I234
STA STAHT+1
LDX #<$1FFF+1
LDY #>$1FFF+1
LDA #START
JSR SAVE
First the starting address is placed in the zero page loca-
tions START and START-i-l. The ending address plus one is
placed in the X (LSB) and Y (MSB) registers and the accumu-
lator is loaded with the address of START. Note that immed-
iate addressing is used because the address itself, not its
192
Advanced Hachlne Language
contents, is intended.
Error messages such as "DEVICE NOT PRESENT" or "MISSING
FILENAME" fflay occur when saving to diskette or "ILLEGAL
DEVICE NUMBER" for an attempt to save to the keyboard,
screen, or RS-232.
Before we try to write our own input/output routines,
we will briefly review the operation of some operating
system kernal routines.
OPEN
For the OPEN command the parameters for the logical
file number, device number, and secondary address are placed
in a table. This table has ten positions. An attempt to
open more than 10 files will generate the error message "TOO
MANY FILES." The rest of the procedure is dependent on the
device number. If the device is the keyboard (0) or the
screen (3), any filename is ignored and the routine ends.
For the datasette (1) a tape file is opened either for
reading (secondary address = 0) or for writing (secondary
address = 1) based on the secondary address. Secondary
address 2 leads to opening a write file and is handled
differently only by the CLOSE command. For reading, the tape
file with the filename given in the OPEN command is searched
for. If no name is given, the first file found is opened.
For writing, a file with the provided name (if any) is
opened.
If the device address is 2, RS-232 transmission is
prepared. As already mentioned, two 256-byte buffers for
input and output are allocated at the upper end of the BASIC
storage. The secondary address is ignored. The first two
193
Advanped Machine Laiiguage
characters of the "filename" are copied to $293 and $294.
From these parameters the nunb^er of„bits per word (5-8) is
calculated and stored in $298. The corresponding baud rate
values with which the timer in CIA 2 must be loaded are
determined from the first character of the filename by means
of a table and savcid in $295/$296. If the X line handshake
was specified, a check is made to see if the signal DSR
(Data Set Ready) is present. In the absence of this signal
the appropriate bit in the RS-232 status ($297) is set.
Otherwise the status is always cleared by the OPEN commjand.
Device addresses greater than 3 refer to the serial
bus. If the secondary address and filename are missing, as
with OPEN 1,4 for the printer, only an entry is made in the
table. The absence of the secondary address must be made
known ta the routine SETFLS by using a negative value ($FF)
for the secondary address. Otherwise the OPEN command is
sent over the serial bus. After the device is addressed with
LISTEN, the secondary address plus $F0 is sent. The connect-
ed device interprets this as an OPEN command. If a filename
was specified, it is sent at the end before the transmission
is ended with UNLISTEN.
CLOSE
The CLOSE command ends the transmissions and clears the
corresponding table entries in the computer. The rest of the
procedure is again determined by the device address. For
files on the keyboard and screen, nothing more is done. If a
tape file is to be closed, the procedure is further depend^
ent on the secondary address. If the file was opened for
reading (secondary address = 0)., nothing more need be done.
For writing, the current contents of the cassette buffer
are written to the tape. For secondary address 2, an EOT
194
Advanced Machine Language
(Knd Of Tape) block is also written. For an RS-232 transmis^
sion, the activities are terminated and the two buffers ar^
deallocated. If a file on the serial bus is to be closed,
the computer sends the secondary address (if there was one^
plus $E0, which is interpreted as a CLOSE conmand.
CHKIN
If the input is to be taken from a file, the conputer
detemines the device number and secondary address from the
logical file number and takes additional steps dependent
upon this. With the datasette, a check is made to see if the
file is a read file (secondary address = 0), otherwise the
error message "NOT INPUT FILE" is generated. For devices on
the serial bus, a TALK command and then the secondary ad-
dress are sent. The device is thereby ready to send data.
The number of the device from which input is to be expected
is stored independent of the device until the normal input
is re-enabled with CLRCH.
CKOUT
The CKOUT command functions like the CHKIN command. For
the datasette, a check is made to see if the secondary
address is greater than zero (otherwise a "NOT OUTPUT FILE"
error). A LISTEN command and the secondary address are sent.
The connected device is then ready to receive data.
BASIN
Here a character is fetched from the keyboard, the
datasette, the RS-232 interface, or the serial bus depending
on the active device selected with CHKIN.
195
Advanced Machine Language
BSOUT
This routine sends the character in the accumulator to
the device previously determined with CKOUT. The screen
serves as the standard device.
CLRCH
The CLRCH command cancels the CHKIN and CKOUT I/O
redirections. The values for keyboard input and 3 for
screen output are again entered. If devices were active on
the serial bus, an UNTALK or UNLISTEN command is sent in
order to inform the devices of the end of the transmission.
196
Advanced Nacblne Language
3.6 Printer spooling
As an example of the use of the input/output vectors of
the operating system, we present a routine that emulates a
Centronics-compatible interface on the user port and also
allows for printer spooling.
Spooling is the outputting of characters to the printer
in the "background," while the computer performs other
tasks. From this description, it should be quite clear that
this must be handled by an interrupt routine. In order that
the normal PRINT output not have to wait until the printer
is ready for each character, we will write the character in
a buffer. The interrupt program checks each time to see if
characters are still in the buffer. If this is so and the
printer is ready to accept more data, characters are sent
until either the printer is no longer ready or there are no
moi'e characters left to be sent.
100:
110:
120:
130:
140:
150:
160:
170:
180:
190:
200:
210:
CCOO
031A
031C
0326
00F7
00F9
.OPT PI
PRINTER SPOOLINQ
I/O VECTORS
OPEN = $31A
CLOSE = $31C
BSOUT = $326
I
WPNT = $F7
RPNT = $F9
;OPEN VECTOR
; CLOSE VECTOR
; BSOUT VECTOR
;WRITE-P0INTER
WITHIN BUFFER
; HEAD-POINTER
WITHIN BUFFER
197
Advanced Machine language
220:
230:
240:
250:
260:
270:
280:
290:
300:
310:
320:
330:
340:
350:
360:
370:
380:
390:
400:
410:
420:
430:
440:
450:
460:
470:
0098
00B8
OOBA
00B9
0259
0263
026D
009B
0001
009A
0314
EA31
F34A
FICA
F31F
F314
F30F
F2A1
F2F1
F6FE
F64B
F291
DDOO
DDOO
DDOl
NRFLS
LF
FA
SA
LFTAB
FATAB
SATAB
CHAR
CONFIG
OUTDEV
IRQVEC
IRQOLD
i
OPENOLD
BSOUTOLD
SETPARA
SEARCHLF
SRCHLFX
OLDCLOSE
CONTCLS
FILEOPEN
TOOMANY
CLOSEOLD
CIA
PORTA
PORTB
; NUMBER OF OPEN
FILES
; LOGICAL FILE
NUMBER
; DEVICE ADDRESS
; SECONDARY ADDRESS
; TABLE OF LOGICAL
FILE NUMBERS
; TABLE OF DEVICE
ADDRESSES
FATAB-t-10 ; TABLE OF
SECONDARY ADDRESSES
; CHARACTER TO BE
OUTPUT
; MEMORY DIVISION
; DEVICE NUMBER
FOR OUTPUT
; IRQ VECTOR
;OL0 IRQ ROUTINE
$98
$B8
$BA
$B9
$259
LFTAB+10
$9E
1
$9A
$314
$EA31
$F34A
$F1CA
$F31F
$F314
$F30F
$F2A1
$F2F1
$F6FE
$F64B
$F291
$DDOO
CIA
CIA+1
;CIA2
;PA2 FOR STROBE
;PORT B FOR DATA
198
480:
490:
500:
DD03
DDOD
Advanced Machine Language
DIRgCTION= CIA+3 ;DATA DIRECTION
REGISTER
ICR = CIA+13 {INTERRUPT CONTROL
REGISTER
510:
EOOO
BUFFER
=
$E000 ; PRINTER BUFFER
UNDER KERNAL
520:
i
530:
CCOO
*=
$CC00
540:
CCOO
A9
OB
INIT
LDA
*<OPENNEW
550:
CC02
AO
CC
LDY
*> OPENNEW
560:
CC04
8D
lA
03
STA
OPEN ; RESET OPEN VECTOR
570:
CC07
8C
IB
03
STY
OPEN+1
580:
CCOA
60
RTS
590:
f
800:
CCOB
A6
B8
OPENNEW
LDX
LF ; LOGICAL FILE
610: CCOD FO 05 BBQ ERROR
620: CCOF 20 OF F3 JSR SRCHLFX
630: CC12 DO 03 BNE ok2
640: CC14 4C FE F6 ERROR JNP FILEOPEN
NUMBER
ZERO NOT ALLOWI^D
; SEARCH FOR FIIjE
DATA
NOT FOUND, OK
; OTHERWISE 'FljLE
OPEN' ERROR
650:
CC17
A6
98
0K2
LDX
NRFLS
; NUMBER OF OPEN
FILES
660:
CC19
EO
OA
CPX
#10
670:
CCIB
90
03
BCC
OK
;LESS THAN 10, OK
680:
CCID
4C
4B
F6
JMP
TOOMANY
; 'TOO MANY FILES'
690:
CC20
A5
BA
OK
LDA
FA
; DEVICE NUMBER
700:
CC22
C9
04
CMP
*4
; EQUAL TO 4?
710:
CC24
FO
03
BEQ
SPOOL
;YES, SPOOLING
720:
CC26
4C
4A
F3
JMP
OPENOLD
730:
CC29
E6
98
SPOOL
INC
NlRFLS
; INCREMENT NUMBER
199
Advanced Machine Language
740:
CC2B
9D
63
02
STA
FATAB , X
; DEVICE ADDRESS
IN TABLE
750:
CC2E
A5
B8
LDA
LF
760:
CC30
9D
59
02
STA
LFTAB.X
; LOGICAL FILE
NUMBER
770:
CC33
A9
FF
LDA
#-1
780:
CC35
9D
6D
02
STA
SATAB.X
;N0 SECONDARY
ADDRESS
790:
CC38
A9
EO
LDA
*>BUFFER
800:
CC3A
85
F8
STA
WPNT+1 ;
WRITE-POINTEH
810:
CC3C
85
FA
STA
HPNT+1 ,
AND READ-POINTER
820:
CC3E
A9
00
LDA
#0 ;
TO START BUFFER
830:
CC40
85
F7
STA
WPNT
840:
CC42
85
F9
STA
RPNT
850:
CC44
A9
FF
LDA
*$FF
860:
CC46
8D
03
DD
STA
DIRECTION ;USER PORT TO
OUTPUT
870:
CC49
AD
00
DD
LDA
PORTA
880:
CC4C
09
04
ORA
#!I!100 ;
STROBE HI
890:
CC4B
8D
00
DD
STA
PORTA
900:
CC51
A9
B5
LDA
*<BSOUTNEH
910:
CC53
AO
cc
LDY
#>BSOUTNEW
920:
CC55
8D
26
03
STA
BSOUT ,
BSOUT VECTOR TO
NEW ROUTINE
930:
CC58
8C
27
03
STY
BSOUT+1
940:
CC5B
A9
DD
LDA
*<CLOSENEW
950:
CC5D
AO
CC
LDY
#>CLOSENEW
CC5F
80
IC
03
STA
CLOSE ;
CLOSE VECTOR TO
NEW ROUTINE
970:
CC62
8C
ID
03
STY
CLOSE+l
980:
CC65
A9
73
LDA
♦<SP00LIN6
990:
CC67
AO
CC
LDY
*>SPOOLING
1000:
CC69
78
SEI
200
1 n 1 n t
oU
1 A
I'x
u o
STA
1020:
CC6D
8C
n o
oil
1030 :
CC70
CO
1040 :
CC71
18
1050 :
CC72
bu
HID
1060:
1
1070:
CC73
A5
01
SPOOLING
LDA
to
PHA
1090:
CC76
A9
35
IDA
1100:
CC78
85
01
STA
1 1 1 n *
1 X X V •
r A
TFSTNKXT
IiDA
fR
o (J
r f
CMP
1130:
CC7E
DO
06
BNE
1 1 •
w ou
FA
LDA
1 1 fin •
CC82
C5
F8
CMP
1160:
CC84
FO
29
BEQ
1170:
CC86
A9
10
SENDCHAR
LDA
1 1 Rn •
X lOll f
2C
OD
DD
BIT
1 1 Qn •
X X 9u *
CC8B
FO
22
BEQ
1 9nn *
rrfin
An
on
LDY
ui.>o r
r 9
LDA
1 ^ ^ U •
8D
1
DD
STA
1230 :
CC94
AD
UU
n n
ill! A
1240:
CC97
29
FB
AND
1250:
CC99
8D
00
DD
STA
1260:
CC9C
09
04
ORA
1270:
CC9E
8D
00
DD
STA
1280:
CCAl
E6
F9
INC
Advanced Machine Language
IRQVEC ; IRQ VECTOR TO
SPOOL ROUTINE
IRQVEC+1
; ERASE ERROR FLAG
CONFIG
#$35 ; SELECT RAM
CONFIG
RPNT ; COMPARE WRITE
POINTER
WPNT ;WITH READ PRINTER
SENDCHAR ; NOT EQUAL, THEN
OUTPUT CHARACTl^R
RPNT+1
WPNT+1
EXIT
#X10000 ;BIT MASK FOR
FLAG
ICR ; PRINTER READY?
EXIT ;N0
*0
(RPNT),Y ; CHARACTER TO
OUTPUT
PORTB ;GIVE TO PORT
PORTA
#*11111011 ; STROBE LO
PORTA
fXOOOOOOlOO ;AND HI AGAIN
PORTA
RPNT
201
Advanced Machine £ancuag<s
1290:
CCA3
DO
D5
BNE
TESTNEXT
; INCREMENT-READ
POINTER
1300;
CCA5
E6
FA
INC
RPNT+1
1310:
CCA7
00
01
BNE
TESTNEXT
1320:
CCA9
A9
BO
LDA
#>BUFFER
1330:
CCAB
85
FA
STA
RPNT+1
1340:
CCAD
DO
CB
BNE
TESTNEXT
;SBND NEXT
CHARACTER
1350:
1
1360:
CCAF
68
EXIT
PLA
1370:
CCBO
85
01
STA
CONFIG
OLD MEMORY
DIVISION
1380:
CCBiZ
4d
31 EA
JMP
IRQOLD
TO ADD IRQ
1390:
1
1400:
CCB5
48
BSOUTNEW
PHA
SAVE CHARACTER
1410:
CCB6
A5
9A
LDA
OUTDEV
DEVICE ADDRESS
1420:
CCB8
C9
04
CMP
#4
EQUAL TO 4?
1430:
CCBA
FO
04
BBQ
OKI
YES
1440:
CCBC
68
PIA
1450:
CCBD
4C
CA Fl
JMP
BSOUTOLD
•TO OLD OUTPUT
1460:
CCCO
68
OKI
PLA
■
CHARACTER BACK
1470:
CCCl
85
9E
STA
CHAR
AND SAVE
1480:
CCC3
98
TYA
1490:
CCC4
4d
PHA
!
SAVE Y
1500:
CCC5
A5
9E
LDA
CHAR ;
CHARACTER
1510:
CCC7
AO
00
LDY
*0
1520:
CCC9
91
F7
STA
(WPNT) ,Y
; WRITE IN BUFFER
1530:
CCCB
E6
F7
INC
WPNT
1540:
CCCD
DO
08
BNE
NOINC ;
INCREMENT BUFFER
POINTER
1550:
CCCF
86
F8
INC
WPNT+1
1560:
CCDl
DO
04
BNE
NOINC
1570:
CCDS
A9
EO
LDA
*>BUFFER
; BUFFER POINTER
202
Advanced Machine Lancuage
TO START
1580:
CCDS
85
F8
STA
WPNT+1
1590:
CCD7
68
NOINC
PLA
1600:
CCDS
A8
TAY
;Y BACK
1610:
CCD9
A5
9E
IDA
CHAR
1620:
CCDB
18
DONE
CLC
{CLEAR ERROR FLAG
1630:
CCDC
60
RTS
1640:
!
1650:
CCDD
20
14
F3
CLOSENEW
JSR
SEARCHLF ; SEARCH FOR FILE
DATA
1660:
CCEO
DO
F9
BNE
DONE ;N0 FILE OPEN,
DONE
1670:
CCE2
20
IF
F3
JSR
SETPARA ;6ET FILE
PARAMETER
1680:
CCE5
8A
TXA
1690:
CCE6
48
PHA
;SAVE X REGISTER
1700:
CCE7
AS
BA
LOA
FA {DEVICE ADDRESS
1710:
CCE9
09
04
CMP
#4 ; 4?
1720:
CCBB
FO
03
BEQ
CLOSEl
1730:
CCED
4C
Al
F2
JMP
OLDCLOSE {OLD CLOSE
ROUTINE
1740:
CCFO
A9
CA
CLOSEl
LDA
*<BSOUTOLD
1750:
CCF2
A2
Fl
LDX
«>BSOUTOLD
1760:
CCF4
8D
26
03
STA
BSOUT {VECTOR TO ADD
BSOUT ROUTINE
1770:
CCF7
8E
27
03
STX
BSOUT+1
1780:
CCFA
Ag
91
IDA
*<CLOSEOLD
1790:
CCFC
A2
F2
LDX
*>CLOSEOLD
1800:
CCFE
8D
IC
03
STA
CLOSE {VECTOR TO OLD
CLOSE ROUTINE
1810:
CDOl
8E
ID
03
STX
CLOSE+1
1820:
CD04
A9
31
LDA
*<IRQOLD
1830:
CD06
A2
EA
LDX
*>IRQOLD
203
Advanced Machine Language
1840:
CD08! '8
SEI
1850: CD09 8D 14 03
1860: CDOC 8B 15 03
1870: CDOF 58
CLI
STA IRQVEC ; REPLACE OLD IRQ
STX IRQVEC-t-1
1880:
CDIO 4C Fl F2
JMP CONTCLS ;BND CLOSE
NORMALLY
JCC00-CD13
NO ERRORS
Before we come to the description of the routine, we
should first learn something about the operation of the
Centronics interface for a better understanding of the
printer output.
A Centronics interface is a parallel interface, meaning
that 8 bits (a complete byte) are always sent in parallel.
In order that the computer and printer be able to agree on
the time of the transmission, two "handshake" lines are
used. The first line is called STROBE and is controlled by
the computer. The line floats high, meaning that it is
normally logically high. If the computer wants to send a
character to the printer, it places the data on the data
lines and signals the printer through a short low impulse on
the STROBE line meaning that the data is ready for it. The
printer accepts the data and forces the BUSY line high until
it has processed the character and is ready to accept the
next. Before the computer can send the next character, it
must first wait until the BUSY line returns to low. The CIA
2 of the Commodore 84 is used for the interface. Port B, the
user port, serves to transmit the data. The STROBE signal
goes over the PA2 line (bit 2 of port A) and the BUSY line
of the printer is connected to the FLAG line of the user
port. Bit 4 in the interrupt control register of the CIA is
204
Advanced Machine Language
automatically set by high to low transition. We can there-
fore recognize exactly when the printer is ready to receive
data. The following timing diagram represents the relation-
ship graphically.
BUSY
DATA
<
>
STROBE
Now to the description of our program. After the def-
inition of the addresses we find first the initialization
which sets the OPEN vector to our new routine in the usual
manner. The routine itself begins in the same way as the
operating system routine with the test of the logical file
number. If it is zero, we output an error message. Otherwise
we search for an open file with this number. If no file with
the same number was opened, we can check to see if ten files
are already open. If so. then the capacity of the file table
is exhausted and we output the error message "TOO MANY
FILES." Otherwise we check the device number. If the device
number is not four, we jump to the normal OPEN routine.
205
Advanced Machine Language
Otherwise we increnent the number of open files and enter
the logical file number, device number, and secondary ad-
dress in the appropriate tables. The buffer pointers are set
to the start of the buffer. We use the 8K from $B000 to
$FFFF under the operating system as the buffer. Then the
user port is switched to output and the STROBE signal is
forced high. Now the vectors for BSOOT and CLOSE are set to
our new routines. The actual spooling is done during the
interrupt; we change the interrupt vector to point to the
routine SPOOLING. After that, the carry flag is cleared and
we can return with HTS.
The spool routine, which is tied into the system inter-
rupt, first switches the memory configuration to RAM and
checks to see if there is a character to output in the
buffer. This is the case if the write pointer, which is
incremented by the routine BSOUT by each write to the buf-
fer, is not the same as the read pointer. If the printer is
now ready to accept characters, we get a byte from the
buffer and place it on the user port. We notify the printer
that we have sent it a valid character by toggling the
STROBE line to low and back to high again. Now we increment
the read pointer so that the next character can be sent from
the buffer.
We now branch to the start of the routine and output
the next character. The loop is executed until either no
characters are left to be sent or the printer is no longer
ready to accept them. At the label EXIT, the normal memory
configuration is switched back on and the normal interrupt
routine is executed.
206
Advanced Machine Language
The routine BSOUTNBW tests to see if the output is
going to device 4. In this case, the character is written
into the buffer and the huffer pointer is incremented. The
routine does not destroy any register contents and is exited
with the cleared carry flag to indicate that no errors
occurred.
In CLOSENEW. the vectors for BSOUT and CIOSE are reset
to the original addresses if the device address four is
recognized. The interrupt vector is also set to its old
value. The output of any characters still in the buffer is
terminated. A loop must be inserted which waits until the
buffer pointers for reading and writing are the sane in
order to avoid this.
A cable is necessary to connect the Commodore 64 user
port to the Centronics interface of the printer. The follow-
ing lines must be connected:
1 PORT - CENTRONICS
A 6ND
16
B FLAG-BUSY
11
C DO
2
D Dl
3
E D2
4
F D3
5
H D4
6
J DS
7
K D6
8
L D7
9
N PA2-STR0BE
1
207
Advanped Machine Language
Since nost printers with a Centronics interface use the
ASCII character set which is different from the Connodore
64's character set, the output can also include a conversion
to ASCII codes.
The following must be noted when starting. Connect the
printer and the computer with the cable and turn on first
the computer and then the printer. This guarantees that the
printer will be in the READY condition and will set the FLAG
bit in the CIA. Now you can load the machine language prog-
ram and initialize it with SYS 52224. After OPEN 1,4, all
data sent via PHINT#1 are written to the buffer, whose
contents are sent to the printer in the interrupt routine.
Writing to the buffer is done very quickly so that your
application program does not have to wait for the printer.
208
Advanced Machine Lanfuage
3.7 Table of BASIC kejrWords and their tokene
Token
Command
Address
Token
Command
Address
$80
128
END
$A831
$9F
159
OPEN
$E1BE
$81
129
FOR
$A742
$A0
160
CLOSE
$E1C7
$82
130
NEXT
$AD1E
$A1
161
GET
$AB7B
$83
131
DATA
$A8F8
$A2
162
NEW
$A642
$84
132
INPUT*
$ABA5
$A3
163
TAB(
-
$85
133
INPUT
$ABBF
$A4
164
TO
-
$88
134
DIM
$B081
$A5
165
FN
-
$87
135
READ
$AC06
$A6
166
SPC(
-
$88
136
LET
$A905
$A7
167
THEN
-
$89
137
GOTO
$A8A0
$A8
168
NOT
-
$8A
138
RUN
$A871
$A9
169
STEP
-
$8B
139
IF
$A928
$AA
170
+
$B86A
$8C
140
RESTORE
$A81D
$AB
171
-
$B853
$8D
141
GOSUB
$A883
$AC
172
*
$BA2B
$8B
142
RETURN
$A8D2
$AD
173
/
$BB12
$8F
143
REM
$A93B
$AE
174
$BF7B
$90
144
STOP
$A82F
$AF
175
AND
$AFE9
$91
145
ON
$A94B
$B0
176
OR
$AFE6
$92
146
WAIT
$B82D
$B1
177
>
-
$93
147
LOAD
$E168
$B2
178
=
-
$94
148
SAVE
$E156
$B3
179
<
-
$95
149
VERIFY
$E165
$B4
180
SGN
$BC39
$96
150
DEF
$B3B3
$B5
181
INT
$BCCC
$97
151
POKE
$B824
$B6
182
ABS
$BC58
$98
152
PRINT*
$AA80
$B7
183
USR
$0310
$99
153
PRINT
$AAAO
$B8
184
FRE
$B37D
$9A
154
CONT
$A6gc
$B9
185
POS
$B39E
$98
155
LIST
$A69C
$BA
186
SQR
$BF71
$9C
156
CLR
$A65E
$BB
187
RND
$E097
$9D
157
CMD
$AA86
$BC
188
LOG
$B9EA
$gE
158
SYS
$E12A
$BD
189
EXP
$BFED
209
Advanced Macbine Language
Token
Coamand
Address
$BE
190
COS
$E264
$BF
191
' SIN
$E26B
$C0
192
TAN
$E2B4
$C1
193
AtN
$E30E
$C2
194
PEEK
$B80D
$C3
195
I EN
$B77C
$C4
196
STR$
$B465
$C5
197
VAl
$B7AD
$C6
198
ASC
$B78B
♦C7
199
CHR$
$B6EC
$CS
200
LEFT$
$B700
$C9
201
RIGHT$
$B72C
$CA
202
MID$
$B737
$CB
203
GO
The table is constructed such that the coninand words
come first ($80-$A2), then the special words which are used
in combination with other commands ($A3-$A9). The operators
are next ($AA-$BO), followed by the comparison operators
($B1-$B3) and the BASIC functions ($B4-$CA). The code for GO
which allows GOTO to be written as GO TO concludes the
table. Behind the command words are the addresses of the
corresponding routines in ROM, whenever possible.
210
FOR COMMODORE-64
HACKERS ONIY !
The ultimate source
for Commo(ldre-64
Computer Infoimation
f ? 3 3 S *
f f 1 J I
1541
DISK
DRIUE
OTHER BOOKS AVAIUBLE SOON
THE ANATOMY OF THE C-64
IS ihe insider's guide to the lesser known features of
the Commodore 64. includes chapters on giapliics.
sound synlhsss. mpul/outpul control, sample progiams
using the kernal routines, more. For those who need lo
know, it includes the complete disassembled and
documented ROM listings.
I SBN>0-91643»00-3 300PP S19.95
THE ANATOMY OF THE 1541
DISK DRIVE
unravels (he mysteries ol using the misunderstood disk
drive. Details the use of program, sequential, relative
and direct access files. Include many sample programs ■
FILE PROTECT. DIRECTORY. DISK tUlONITOR. BACKUP.
MERGE. COPY, others Describes internals of DOS with
completely disaddembiEd and commenied listings of the
1541 ROMS
ISBN*0*01 6439-0 1-1 320pp S 1 9.95
MACHINE UANGUAGE FOR C-64
IS aimed at those who want to progress tieyond BASIC
Write faster, more memory efficient programs iti machine
language. Test is specifically geared to Commodore 64
Learns all 6510 instruclions. Includes listings for 3 full
length programsf ASSEMBLER. DISASSEMBLER and
amazing 6510 SIMULATOR so you can "see" the opera-
tion of the '64.
ISBN-0-916439-02- X 200pp t14.95
TRICKS & TIPS FOR THE C-64
IS a coUectton ol easy-to-use programming techniques lor
the '64, A perfect companion for those who riave run
up against (hose hard to solve programming prooiems
Covers advanced graphics, easy data input. BASIC
enhancements. CP/M cartridge on the '64, POKEs. user
detined character sets, joystick/mouse stmulatton. trans-
ferring data between comulers. more. A treasure chest
I8BN-0-916439-03-8 250pp $19.95
GRAPHICS BOOK FOR
THE C-64
takes you from the lundamenials of graphic to
advanced topics such as computer aided design. Shows
you how to program new character sets, move sprites,
draw m HIRES and MULTICOLOR, use a ligMpen.
handle IROs. do 3D graphics, projections, curves and
animation. Includes dozens ol samples.
ISBN-0-916439-0S-4 280pp $19.95
ADVANCED MACHINE
LANGUAGE FOR THE C-64
gives you an intensive treatment of the powerful 64
leatures. Author Lothai Englisch delves into areas such
as interrupts, the video controller, the timer, the real
lime clock, parallel and serial I/O. extending BASIC and
tips and incks Irom machine language, more
ISBN-0-9 16439-06-2 200pp $14.95
IDEAS FOR USE ON YOUR C-64
IS for those who wonder what you can do with your '64
II IS written for the novice and presents dozens of
program listing Ihe many, many uses for your
computer Themes include: auto expenses, electronic
calculator, recipe file, stock lists, construction cost
estimator, personal health record diet planner, store
window advemstng. computer poetry, party invitations
and more
ISBN-0-916439-07-0 200pp S12.9S
PRINTER BOOK FOR THE 0-64
finally simplifies your understanding of the 1525.
MPS/801. 1520. 1526 and Epson compatible printers.
Packed with examples and utility programs, you'll learn
how 10 make hardcopy of text and graphics, use secon-
dary addresses, plot in 3-D. and much more. Includes
commented listing of MPS SOI ROMs.
ISBN-0-9 16439-08-9 3S0pp. $19.95
SCIENCEfENGINEERING
ON THE C-64
IS an mlroduclion to the worM of computers in science.
Describes variable types, computational accuracy,
various sort alogrithms Topics include linear and
nonlinear regression. CHI-square distribution. Fourier
analysis, matrix calculations, more Programs Irom
chemistry, physics, biology, astronomy and electronics.
Includes many program listings
ISBN- 0-916439-09-7 250pp $19.95
CASSETTE BOOK FOR THE C-64
(or Vic 20) contains ail the information you need to
know about using and programming the Commodore
Datasette includes many example programs. Also con-
tains a new operating system lor fast loading, saving
and finding of files
ISBN-0-01 6439-04-6 180pp. $12.95
DEALER INQUIRIES ARE INVITED
IN CANADA CONTACT)
The Book Csntre, 1140 Beaulae Street
Montreal. Quebec H4BiRe Phone: 1S14) 322-4154
AVAILABLE AT COMPUTER STORES, OR WRTTE:
/teifi 111 Software
P.O. BOX 721 1 GRAND RAPIDS. Mi 49S10
CichMltft U.8. DATA BECKER Publltlwn
For pottage & handling, idd M.OO (U.S. and ■
Canada).*(tdte.OOforfor0i0n.Mak«paymflnl |
in U.S. dollars by check, monay order of
charge card. (Michigan Realdents add 4% I
Bslea lax.) "
FOR QUICK SERVICE PHONE (616) 241-5610
Commodor* 64 M ■ reg. T.M. ol Commodora Builiwu MadiiiM
GETTHE MOST OUT OF von
OOMMODORE-64
WITH ABACUS SOFTWARE
XREF-64 BASIC CROSS REFERENCE
This tool allows you to locale those hard-to-lind variables in your programs.
Croiss-feferences all tokens (key words), variables and conslanis m sorted
order. You can even add you own tokens from other software such as
ULTRABASIC or VICTREE. Listings to screen or all ASCII printers.
DISK $17.95
SYNTHY-64
This is renowned as the finest muspc synthesizers available at any price.
Others may have a lot of onscreen Inlls. but SYNTHY-64 makes music belter
than them all. Nothing comes close to the performance of this package.
Includes manual with tutorial, sample music.
DISK S27.95 TAPE S24.9S
ULTRABASIC-64
This package adds 50 powerful commands (many found m VIDEO BASIC,
above) • HIRES, miJl DOT. DRAW. CIRCLE, BOX. FILL. JOY. TURTLE,
MOVE. TURN, HARD. SOUND. SPRITE. ROTATE, more. All commands
are easy to use. Includes manual with two-part tutorial and demo.
DISK S27.9S TAPE $24.95
CHARTPAK-64
This finest charting package draws pre. bar and line charts and graphs Irom
your data or DIP, Multiplan and Busicalc files. Charts are drawn in any of
2 formats. Change format and build another chart immediately. Hardcopy
to r^PS601. Epson, Okidala. Prownler. Includes manual and tutorial.
DISK S42.95
CHARTPLOT-64
Same as CHARTPACK-64 for highest quality output to most popular pen
plotters. DISK Se4.9S
DEALER INQUIRIES ARE INVITED
CADPAK-64
This advanced design package has outstanding features - two Hires
screens; draw LINES. RAYs. CIRCLES, SOXEs; freehand DRAW; FILL with
patterns; COPY areas; SAVE/RECALL pictures; define and use intricate
OBJECTS; inseil text on screen; UNDO last function. Requires high quality
lightpen. We recommend UcPen. Includes manual with tutorial.
DISK S49.95 . McPen llghlpen $49.9S
MASTER 64
This prolessional application developmenl package adds 100 powerful
commands lo BASIC including fast ISAM indexed files: Simplified yet
sophisticated screen and printer management; programmer's aid; BASIC
4.0 commands; 22-digit arithmetic; machine language monitor. Runtime
package tor royalty-free distribution ol your programs. Includes 150pp.
manual.
* DISK $84.95
VIDEO BASIC-64
This superb graphics and sound development package lets you wnle soft-
ware for distribution without royalties. Has hires, multicolor, sprite and
turtle graphics; audio commands for simple or complex music and sound
effects; two sizes of hardcopy to most dot matrix printer^; game features
such as sprite collision detection, lightpen, game paddle; memory
management for multiple graphics screens, screen copy, etc.
DISK $59.95
TAS-64 FOR SERIOUS INVESTORS
This sophisticated charting system plots more than 15 technical indicators
on split screen; moving averages; oscillators; trading brands; least squares;
trend lines; supenmpose graphs; five volume indicators; relative strength;
volumes, more. Online data collection DJNR/Sor Warner. t75pp. manual.
Tutorial DISK $84.95
FREBCATALOa Ask for a listing of othsr
AlMCUS Software for Commodore-64or Vle-20
DISnillUTOM
SmllilWK Minm: fmm: SSUmHrSciooiiics
mmon ii»r.s«»im uicia«m.cATioii I^PfJiSS^
RocMili, Lmi. Bnml 1in, Mp«ii Kuril MUmilioa, Fnnn gsS" '<"'•
70U!43b4 Hn-U47 m-KU 6MM«
WM etnumf: IvMn: Amliilla:
MT* KCan TIM. TRAOmS CW ELECTMWIIS
Mnailngnti 30 WSie 41> Logui RoU
jMODlMdnl 94300 AMnin BiHbuo, OuHns
01ll/)U06i 476-12304 07^4800
Comrmilora 64 is a reg. T.M. of Commodore Business Machlnas
AVAILABLE AT C OMPUTER STORES, OR WRITE:
/Abacus ■ SoftNA/are
P.O. BOX 7211 GRAND RAPIDS. MICH. 49S10
For posttgi & htndftig, odd S4.00 (U.S. ind Canadt), tdtf 18.110
tor foreign. Mika uymtnt bi U.S. ifogirs by cheidi, money onlor
or clurga card. (M&lilgan RasUtim add 4% salts tax).
FOR QUICK SERVICE PHONE 616-241-5S10
PASCAL-64
This full compiler produces last 6502
machine code. Supports major data Types:
REAL. INTEGER, BOOLEAN. CHAR,
multiple dimension arrays. RECORD, FILE,
SET and pointer. Offers easy string handl-
ing, procedures for sequential and relative
data management and ability to write IN-
TERRUPT routines in Pascal! Extensions
included for ftigh resolution and sprite
graphics. Link to ASSEM/MON machine
language. DISK $39.95
DATAMAT-64
This powerful data base manager handles
up to 2f]00 records per disk. You select the
screen format using up to 50 fields per
record. DATAMAT 64 can sort on multiple
fields in any combination. Complete report
writing capabilities to all COMMODORE or
ASCII printers. disk $39.93
Available November
TEXTOMAT-64
This complete word processor displays 80
columns using horizontal scrolling. In
memory editing up to 24.000 characterrs
plus chaining of longer documents.
Complete text formatting, block operations,
form letters, on-screen prompting.
Available November DISK $39.95
ASSEMBLER /
MONITOR-64
This complete language development
package features a macro assembler and
extended monitor. The macro assembler
offers freelorm input, complete assembler
listings with symbol table (label), condi -
tkjnal assembly.
The extended monitor has all the standard
commands plus single step, quick trace
breakpoint, bank switching and more.
DISK $39.95
BASIC-64
This is a full compiler that won't break your
budget. Is compatible with Commodore 64
BASIC. Compiles to fast machine code.
Protect your valuable source code by com-
piling with BASIC 64.
Available December Q|g|^ $39.95
ADA TRAINING COURSE
This package is an introduction to ADA. the
official language ot the Department ol
Defense and the programming language of
the future. Includes editor, syntax
checker/compiler and 110 page step by
step manual describint the language.
Available November
DISK $79.95
OTHER NEW SOFTWARE COMINO SOONI
All software products featured above
have inside disk storage pockets,
and heavy 3-ring-binder for maxi-
nnum durability and easy reference.
DEALER INQUIRIES INVITED
AVAILABLE AT COMPUTER STORES, OR IMVTE:
AbECusiilSoftwane
P.O. BOX 7211 QRANO RAPIDS, Ml 49t10
Exclullvt U.t. DAT* IICKCR PllUMm
For pMttgt a htndlng, add MAO (U.8. ind
CvinUI. M<IH.OOIor loiilgn. Mala peyiMM
In U.S. doim ti ciMck, moMy order ol
cinrgi card. (MtcMgan RoiUonti odd 4«t
HIM lax.)
FOR QUICK SERVICE PHONE (S1«) 241-SS10
e4tt«i«B.T.M.0l
MACHIME
FDR THE
COMMODQRE-64
This ^ook is packfid with new and useful ways to
enhance your knowledge of the '64- Vou ll Isarn how
lo use interrupts, add new BASIC keywords, access;
the real Lime ClOC^r perlornn I/O all from machine
language. Includes many sample programs anci'
machine latiguage tips for the serious prog/rammer.
Software
P.O. BOX 7211 GRAND RAPIDS, MICH. 49510 PHONE 616-^41